remove array items where only one field is non-unique

This topic contains 2 replies, has 2 voices, and was last updated by Profile photo of Ian Douglas Ian Douglas 3 years, 7 months ago.

  • Author
    Posts
  • #10365
    Profile photo of Ian Douglas
    Ian Douglas
    Participant

    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

  • #10366
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    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.

  • #10369
    Profile photo of Ian Douglas
    Ian Douglas
    Participant

    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!

You must be logged in to reply to this topic.