Author Posts

September 25, 2013 at 10:04 am

I'm creating a script to query installed software. I'm using the the uninstall key and the win32_product class, and I want to collate results and eliminate entries with duplicate names.
I'm able to collate results but removing results with duplicate names evades me. Any help would be most appreciated!

here is what i have so far:


$productReg = Get-ChildItem registry::hklm\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { (Get-ItemProperty $_.pspath) }

$productWMI = Get-WmiObject win32_product

$products = @()

$productReg | % {

$obj = New-Object psobject -Property @{

Vendor = $_.publisher
Name = $_.displayname
Version = $_.displayversion

}

$products += $obj

}

$productWMI | % {

$obj = New-Object psobject -Property @{

Vendor = $_.vendor
Name = $_.name
Version = $_.version

}

$products += $obj

}

$products

September 25, 2013 at 10:14 am

So if I understand your requirement correctly, if you've already got an object with that Name, you don't want to add any more with the same Name to the collection? For that, I'd probably use a hash table instead of an array. The code changes might look something like this:

$productReg = Get-ChildItem registry::hklm\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { (Get-ItemProperty $_.pspath) }
$productWMI = Get-WmiObject win32_product

$products = @{}

$productReg | % {
    $obj = New-Object psobject -Property @{
        Vendor = $_.publisher
        Name = $_.displayname
        Version = $_.displayversion
    }
    
    if (-not $products.ContainsKey($obj.Name))
    {
        $products[$obj.Name] = $obj
    }
}

$productWMI | % {
    $obj = New-Object psobject -Property @{
        Vendor = $_.vendor
        Name = $_.name
        Version = $_.version
    }
    
    if (-not $products.ContainsKey($obj.Name))
    {
        $products[$obj.Name] = $obj
    }
}

$products.Values

On a side note, that Win32_Product class is kind of evil. Querying it causes your system to run a consistency check of every Windows Installer package on your system, instead of just listing what's installed. I don't know why, but that's what it does. Check your disk activity and Application Event Log after running a "Get-WmiObject Win32_Product" command, and you'll see what I mean.

September 25, 2013 at 10:55 am

Dave,

This solves my problem, thank you so much. I did need to modify the conditional to the following:

if ($obj.name -ne $null -and -not $products.ContainsKey($obj.Name))

— to account for the case where name is null and to skip it.

Thanks for the tip about win32_product. I'm using the above code as a scriptblock in a remoting script, so given what you've just said, I should probably wait until after business hours to run it!