Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell, Get-Unique blowing away already-unique, single objects

Tags:

powershell

I'm gathering information from an xml file and processing it. My queries are liberal in order to make sure I get all the possible elements I want. As a result, it's possible to end up with duplicate elements in the result list (called $components). I ran the result through Sort-Object and then Get-Unique to find all unique objects. It is my understanding that one of each unique object should be left by Get-Unique. But it's eliminating some of the already-unique objects (objects that have no duplicates in the original list).

Here is a simplified example. Just paste this into PowerShell or save to ps1 file and run (output shown below):

$xmlDoc = [xml]@'
<root>
    <component Id='component1'>
        <regkey Id='regkey1'/>
    </component>
    <component Id='component2'>
        <file Id='file1' />
    </component>
</root>
'@

$files = $xmlDoc.SelectNodes("//file[@Id='file1']")
$regkeys = $xmlDoc.SelectNodes("//regkey[@Id='regkey1']")
$components = $xmlDoc.SelectNodes("//component[@Id='component1'] | //component[@Id='component2']")
$components += $regkeys | Select-Object -ExpandProperty 'ParentNode'
$components | Sort-Object -Property 'Id'
Write-Host
$components | Sort-Object -Property 'Id' | Get-Unique

If you pasted into PowerShell, hit enter after that last line.

The output is like this:

PS C:\> $xmlDoc = [xml]@'
>> <root>
>>     <component Id='component1'>
>>         <regkey Id='regkey1'/>
>>     </component>
>>     <component Id='component2'>
>>         <file Id='file1' />
>>     </component>
>> </root>
>> '@
>>
PS C:\> $files = $xmlDoc.SelectNodes("//file[@Id='file1']")
PS C:\> $regkeys = $xmlDoc.SelectNodes("//regkey[@Id='regkey1']")
PS C:\> $components = $xmlDoc.SelectNodes("//component[@Id='component1'] | //component[@Id='component2
']")
PS C:\> $components += $regkeys | Select-Object -ExpandProperty 'ParentNode'
PS C:\> $components | Sort-Object -Property 'Id'

Id                                                 regkey
--                                                 ------
component1                                         regkey
component1                                         regkey
component2


PS C:\> Write-Host

PS C:\> $components | Sort-Object -Property 'Id' | Get-Unique

Id                                                 regkey
--                                                 ------
component1                                         regkey


PS C:\>

Notice how component2 disappears entirely once we pipe to Get-Unique. Can anyone explain this and offer a fix that keeps the query scheme about the same?

Edit: I assumed it would use the -eq operator to see if the elements were references to the same object in memory. If I manually try -eq it shows the correct objects being equal. But Get-Unique seems to be doing something else. If you add this code to the end of the above script it shows the object equivelance:

Write-Host
Write-Host "0: $($components[0].Id)"
Write-Host "1: $($components[1].Id)"
Write-Host "2: $($components[2].Id)"
Write-Host ("0 vs 1: " + ($components[0] -eq $components[1]))
Write-Host ("0 vs 2: " + ($components[0] -eq $components[2]))
Write-Host ("1 vs 2: " + ($components[1] -eq $components[2]))

The output (when run from script file):

0: component1
1: component2
2: component1
0 vs 1: False
0 vs 2: True
1 vs 2: False
like image 661
Vimes Avatar asked May 02 '26 13:05

Vimes


1 Answers

You can use the -unique flag of sort-object. That gives the expected result for me:

$components | Sort-Object -Property 'Id' -Unique
like image 97
manojlds Avatar answered May 05 '26 08:05

manojlds