powershell color output if matches condition - powershell

Firstly, I have a csv file with a list of programs that should be included with the default installation of Windows. The CSV looks like this.
Name;Version;Vendor;InstallDate
64 Bit HP CIO Components Installer;18.2.4;Hewlett-Packard;20210902
7-Zip 18.05 (x64 edition);18.05.00.0;Igor Pavlov;20210812
Adobe Acrobat Reader DC;20.006.20034;Adobe Systems Incorporated;20210903
Secondly, I have a powershell script that tries to compare the list of programs on a remote computer with the list of programs in the CSV file (by Name, Version and Vendor). It is supposed to output only the non matching programs.
The comparing part works perfectly, but now I would like to color the lines of output which match by Name and Vendor, but not by Version. How would I go about doing that?
This is my powershell script.
$programs =#()
$programs = Get-WmiObject –computername <ComputerName> -Class Win32_Product
foreach($program in $programs) {
foreach($defprogram in Import-Csv -Path "...\defprograms.csv" -Delimiter ';') {
if ($program.Name -eq $defprogram.Name -And $program.Version -eq $defprogram.Version -And $program.Vendor -eq $defprogram.Vendor) {
$programs = $programs -ne $program }
}}
$programs | sort-object Name | format-table -AutoSize Name,Version,Vendor,InstallDate
And this is the output of fore mentioned script.
In the example in the output, I would like to make the '64 Bit HP CIO Components Installer' colored red.
64 Bit HP CIO Components Installer 15.2.1 Hewlett-Packard 20210909
Canon Laser Printer/Scanner/Fax Extended Survey Program 2.1.2 CANON INC. 20210216

Not a nice solution, but do the job :
$a = #"
Name;Version;Vendor;InstallDate
64 Bit HP CIO Components Installer;18.2.4;Hewlett-Packard;20210902
7-Zip 18.05 (x64 edition);18.05.00.0;Igor Pavlov;20210812
Adobe Acrobat Reader DC;20.006.20034;Adobe Systems Incorporated;20210903
"#
$b = $a | Convertfrom-Csv -Delimiter ';'
$b | % {Write-Host "$($_.name);" -ForegroundColor Red -NoNewline; Write-Host "$($_.Vendor);" -NoNewline; Write-Host $($_.Installdate) ;}

You can do this by reading the CSV with default programs you need to colorize.
Then create a regex string of their .Name property. Use Format-Table as usual, but append Out-String -Stream so you can capture the resulting lines in a variable
# your code here:
$programs = #(Get-WmiObject –computername <ComputerName> -Class Win32_Product)
foreach($program in $programs) {
foreach($defprogram in Import-Csv -Path "...\defprograms.csv" -Delimiter ';') {
if ($program.Name -eq $defprogram.Name -And $program.Version -eq $defprogram.Version -And $program.Vendor -eq $defprogram.Vendor) {
$programs = $programs -ne $program }
}
}
# read the default programs and create a regex string of their Name fields
$defprograms = Import-Csv -Path "...\defprograms.csv" -Delimiter ';'
$redprograms = '({0})' -f (($defprograms.Name | ForEach-Object { [regex]::Escape($_) }) -join '|')
# Format-Table the array of objects and capture the resulting lines in variable `$table`
$table = $programs | Sort-Object Name | Format-Table -AutoSize Name,Version,Vendor,InstallDate | Out-String -Stream
# next loop through these lines and find lines that match any of the default program names
switch -Regex ($table) {
"^$redprograms\s*" {
Write-Host $_.Substring(0, $matches[1].Length) -NoNewline -ForegroundColor Red
Write-Host $_.Substring($matches[1].Length)
}
default { $_ }
}
Output would then look something like

Related

Powrshell to export list of all PCs and if they have specific application install

I currently use the following powershell script to export the list of all VMs on our network with their information and export into an excel file:
#// Set CSV file name
$uDateTime = Get-Date -f "yyyy-MM"
$uCSVFile = "C:\Servers"+$uDateTime+".csv"
#//Export out to csv file.
Get-ADComputer -filter * -Properties ipv4Address, OperatingSystem,DistinguishedName |
select-object Name, ipv4Address, OperatingSystem, #{label='OU';expression=
{$_.DistinguishedName.Split(',')[1].Split('=')[1]}} |
export-csv -path $uCSVFile
The excel content would look something like this:
I want to add another column to indicate if specific application exists on each server or not like this one
Upon googling around I see that I can utilize the Get-ItemProperty to read the registry in order to check if certain program is installed on individual VM, but I am having problem tying the code to my existing one. It gives me the same result based on the machine where this PowerShell scripts runs on instead of each VM registry individually ...
Can you help me making this script read each VM's registry
#// Set CSV file name
$uDateTime = Get-Date -f "yyyy-MM"
$uCSVFile = "C:\Servers"+$uDateTime+".csv"
#//Export out to csv file.
Get-ADComputer -filter * -Properties ipv4Address, OperatingSystem,DistinguishedName |
select-object Name, ipv4Address, OperatingSystem, #{label='OU';expression=
{$_.DistinguishedName.Split(',')[1].Split('=')[1]}},
#{label='HelloKitty Installed';expression={(Get-ItemProperty "HKLM:\Software\HelloKitty\*" | Where {
$_.Version -ne $null }) -ne $null}}|
export-csv -path $uCSVFile
To read a registry key from the computer you are targetting instead of the computer the script is currently running from, you should use the Invoke-Command cmdlet.
However, keep in mind that Get-ADComputer can also list computers that are currently off-line, so I would suggest using a ForEach-Object loop which will give you a chance to test for that first.
Something like this:
#// Set CSV file name
$uCSVFile = 'C:\Servers{0:yyyy-MM}.csv' -f (Get-Date)
#//Export out to csv file.
$result = Get-ADComputer -Filter * -Properties ipv4Address, OperatingSystem,DistinguishedName |
ForEach-Object {
if (Test-Connection -ComputerName $_.Name -Count 1 -Quiet) {
# computer is on line. If need be, add -Credential to the Invoke-Command cmdlet
# because reading the HKEY_LOCAL_MACHINE hive needs Administrator permissions.
# Also, the targetted machines must have the 'Remote Registry' service enabled.
try {
$installed = Invoke-Command -ComputerName $_.Name -ScriptBlock {
$null -ne (Get-ItemProperty "HKLM:\SOFTWARE\HelloKitty\*" |
Where-Object { $null -ne $_.Version }).Version
} -ErrorAction Stop
}
catch { $installed = "ERROR" }
}
else { $installed = "OFF-LINE" }
# output an object
$_ | Select-Object Name, ipv4Address, OperatingSystem,
#{Name = 'HelloKitty Installed'; Expression = { $installed }}
}
# now export to CSV
$result | Export-Csv -Path $uCSVFile -UseCulture -NoTypeInformation
I have added switch -UseCulture to the Export-Csv cmdlet so the delimiter character used in the csv file will be the same as your local Excel expects

Get specific info on domain computers from AD OUs

I'm trying to Get the Name, Manufacturer, and model of computers so i can distinguish what computers are out of warranty in AD.
I'm trying to do this by getting the computer names and putting there info into the corresponding .csv file but this fails and puts 1 ou to multiple .csv files and then moves to the second ou and does the same thing?
$myMultiArray = #(("OU=Domain Controllers,DC=FABRIKAM,DC=COM"),
("OU=Computers,DC=FABRIKAM,DC=COM"))
$myFileArray = #(("‪D:\VS-Code\Powershell\AD_Computer_Management\OUs\Domain
Controllers.csv"),("‪D:\VS-
Code\Powershell\AD_Computer_Management\OUs\Computers.csv"))
foreach ($MultiOU in $myMultiArray) {
Get-ADComputer -Filter * -SearchBase $MultiOU -SearchScope 2 | Select-object Name | Out-File -FilePath "D:\VS-Code\Powershell\AD_Computer_Management\OUs\garbage.csv"
For ($i = 0; $i – $myFileArray.Length - 1; $i++) {
Write-Host $myMultiArray[$i]
[string[]]$cnArray = Get-Content -Path 'D:\VS-Code\Powershell\AD_Computer_Management\OUs\garbage.csv'
Write-Host $OU
if ($i -eq $i) {
foreach($CN in $cnArray){
Get-WmiObject -Class:Win32_ComputerSystem -ComputerName $OU | Format-List -Property Name, Manufacturer, Model | Out-File -FilePath $myFileArray[$1]
}
}
}
}
I've tried multiple variations of different loops and if statements.
I think there are two things:
Out-File -FilePath $myFileArray[$1]
Should be:
Out-File -FilePath $myFileArray[$i]
And also you might need to append:
Out-File -FilePath $myFileArray[$i] -Append
There are a couple of things wrong in your code, like $i – $myFileArray.Length, which should be $i –lt $myFileArray.Length.
Then there is Out-File -FilePath $myFileArray[$1] as Bernard Moeskops already mentioned.
Also your code seems to want to create both the Domain Controllers.csv aswell as the Computers.csv files regardless of the OU you are currently in.
Lastly, you are using Out-File to create the CSV files where for proper CSV output, you should use the Export-Csv cmdlet.
The following code should do what you want:
$myOUArray = "OU=Domain Controllers,DC=FABRIKAM,DC=COM", "OU=Computers,DC=FABRIKAM,DC=COM"
$myFilePath = "‪D:\VS-Code\Powershell\AD_Computer_Management\OUs" # just the path for the output files is needed
foreach ($OU in $myOUArray) {
# determine the file name from the OU we're in
$fileName = if ($OU -match 'OU=Domain Controllers') { 'Domain Controllers.csv' } else { 'Computers.csv'}
$filePath = Join-Path -Path $myFilePath -ChildPath $fileName
Write-Host "Getting computer info from OU '$OU'"
# get a string array of the computernames found in the OU
$computers = Get-ADComputer -Filter * -SearchBase $OU -SearchScope Subtree | Select-Object -ExpandProperty Name
# loop through this array to get the properties you want for
# each computer and store that as objects in the $result variable
$result = foreach($machine in $computers){
Get-WmiObject -Class:Win32_ComputerSystem -ComputerName $machine | Select-Object -Property Name, Manufacturer, Model
}
Write-Host "Creating file '$filePath'"
# save the CSV file to disk
$result | Export-Csv -Path $filePath -NoTypeInformation -Force
}

Powershell reg enquiry and table formation

$array = #()
$path="C:\Reports\Software.txt"
$programs = Get-Content -Path $Path;
foreach ($program in $programs)
{
$system64=Get-ItemProperty
HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
Select DisplayName, DisplayVersion | where {$_.DisplayName -like
"*$program*"};
$system32=Get-ItemProperty
HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select
DisplayName, DisplayVersion| where {$_.DisplayName -like "*$program*"};
if ($system64)
{
Write-Host "npp query = "$system64""
Write-Host "npp query = "$system32""
Write-Host -ForegroundColor green "$program already installed!"
$array += $system64
}
elseif ($system32)
{
Write-Host "npp query = "$system64""
Write-Host "npp query = "$system32""
Write-Host -ForegroundColor green "$program already installed!"
$array += $system32
}
else
{
$array += $program
}
}
$array |Export-Csv C:\Reports\Software.csv -NoType
I am trying to create a table with specific software I have on my computer and their Version.
I would like if the Software doesn't exit to put software name under the header DisplayName and under the header DisplayVersion to put Not Installed.
It works fine if the software exists but if it doesn't it doesn't put the name under the header and put a blank line on the excel file.
example what I am taking now is :
DisplayVersion DisplayName
Gimp 2.8.22
7-Zip 18.01
Notepad++ 7.5.8
What i Want
DisplayVersion DisplayName
Gimp 2.8.22
7-Zip 18.01
Adobe Acrobat Not Installed
Notepad++ 7.5.8
any suggestions ?
Give this one a try in your else statement:
$array += #(1 | Select-Object #{Name="DisplayName";Expression={$program}},#{Name="DisplayVersion";Expression={'not installed'}})
With this, you create a custom object and add it to your array.
Hope it helps.

Work with ADComputer output in foreach loop

I want to output all hostnames within a network first with a foreach loop, in order (for example) to be able to ping them.
However with the following code I do not get any output in the console. The CSV file will be saved, but what is written in the loop will not be executed.
Does anyone know what the reason for this is and how I can solve it?
Import-Module activedirectory
Get-ADComputer -Filter * -Property * | Select Name | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8 | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
}
This occurs because Export-CSV does not output an object. Sometimes cmdlets like this have a -PassThru parameter which you can use to have an object passed along, but thats not the case with Export-CSV, they simply expect it to always be the last cmdlet in the pipeline.
You should instead do this:
$Computers = Get-ADComputer -Filter * -Property * | Select Name
$Computers | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8
$Computers | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
}
You could also do this:
Get-ADComputer -Filter * -Property * | Select Name | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
$_
} | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8
Noting that we have to add $_ to our ForEach-Object loop so that it outputs the current item to the pipeline, but that our Write-Host statements don't effect the pipeline because they are writing to the console only. To be honest though, this is a bit harder to follow for anyone else reading your code.

Run command dependent on OS and IF service is present

I have 2 scripts as follows that gets websites for IIS.
IIS 6 -
$website = Get-WmiObject -Class IIsWebServerSetting -Namespace "root\microsoftiisv2" | Select ServerComment | Format-Table -HideTableHeaders | out-file c:\website.txt
$b = Get-Content -Path C:\website.txt
$b | ForEach {$_.TrimEnd()} | ? {$_.trim() -ne '' } > C:\website.txt
$b = Get-Content -Path C:\website.txt
#(ForEach ($a in $b) {$a.Replace(' ', '')}) > C:\website.txt
Get-Content C:\website.txt
IIS 7+
Import-Module webadministration
$a = Get-Website | Select-Object Name
$a | ForEach-Object {
$_.name = $_.name.replace(" ","")
}
$a | Format-Table -HideTableHeaders | Out-File $DeviceDrive\Apps\NetprobeNT\Auto-monitor\Website.txt
$b = Get-Content -Path $DeviceDrive\Apps\NetprobeNT\Auto-monitor\Website.txt
$b | ForEach {$_.TrimEnd()} | ? {$_.trim() -ne '' } > $DeviceDrive\Apps\NetprobeNT\Auto-monitor\Website.txt
$b = Get-Content -Path $DeviceDrive\Apps\NetprobeNT\Auto-monitor\Website.txt
#(ForEach ($a in $b) {$a.Replace(' ', '')}) > $DeviceDrive\Apps\NetprobeNT\Auto-monitor\Website.txt
I have a different script for IIS 6 (Windows 2003 hosts) because webadministration module is not available for II6.
I need to add an if statement that will add logic to run the correct code dependent on the host operating system and if W3SVC service (World Wide Web Publishing Service) is present (running or stopped). Something along the lines
IF W3SVC is present
Check host operating system
IF operating system = Windows 2003
Run II6 code
Else
Run II7+ code
I don't know where to begin with this script. PowerShell and scripting is new to me and this is part of my first script I am creating. Any help will be greatly appreciated.
I can get the host operating system but confused on how I would put logic into it to get the results I need.
(Get-WmiObject Win32_OperatingSystem).Name
Use Caption rather than Name. Other than that you simply plug the routine into your pseudocode:
if ((Get-WmiObject Win32_OperatingSystem).Caption -eq 'Windows 2003') {
# Run II6 code
} else {
# Run II7+ code
}
For the service you can use the Get-Service cmdlet:
if (Get-Service -Name w3svc -ErrorAction SilentlyContinue) {
...
}
or Get-WmiObject on the Win32_Service class if the Get-Service cmdlet isn't available in PowerShell v2 (not sure about that):
if (Get-WmiObject Win32_Service -Filter "Name='w3svc'") {
...
}