1

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
mklement0
  • 382,024
  • 64
  • 607
  • 775
jerkdavi
  • 47
  • 2
  • 9
  • 3
    To be real honest you're better off converting to an HTML table, saving the HTML as a file, and then opening the file. Then you can do all the pretty formatting you want with the HTML. To do it in PowerShell, well, when I did it, I converted the table to strings with `Out-String`, parsed that with RegEx, and then did several `Write-Host` commands per line with the `-NoNewLine` parameter on all the but the last part of the line and define colors as appropriate. – TheMadTechnician Sep 16 '21 at 19:43
  • 2
    Does this answer your question? [Powershell - Output Color for certain results](https://stackoverflow.com/questions/46016763/powershell-output-color-for-certain-results) – Adrian Kokot Sep 16 '21 at 19:57
  • Unfortunately, it does not answer my question. I want to avoid typing the exact line that needs to be colored. I have a list of xy programs, which is likely to change in the future. Furthermore, the versions of the programs are also changing. I want the line colored if the program name and program vendor from remote computer match the program name and program vendor in the csv file, no matter what the remote computer and csv file consist of. – jerkdavi Sep 16 '21 at 20:27

2 Answers2

2

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) ;}
JPBlanc
  • 70,406
  • 17
  • 130
  • 175
  • Is there any way I could do that without specifying program names in code, but only by the if command which compares the objects imported from remote computer with the objects imported from csv file (no matter what is installed on the remote computer and what is written in the csv file)? – jerkdavi Sep 17 '21 at 09:06
1

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

enter image description here

Theo
  • 57,719
  • 8
  • 24
  • 41
  • 1
    Wow! I am not gonna lie, I do not understand how this works, but it does exactly what I need of it. @Theo, thank you very much man! – jerkdavi Sep 17 '21 at 14:27