Comparing and Grouping Data
Prerequisites: Custom objects, Working with CSV
Compare-Object
Compare-Object finds the differences between two sets:
$expected = 'nginx', 'redis', 'postgres', 'cron'
$running = 'nginx', 'postgres', 'sshd'
Compare-Object -ReferenceObject $expected -DifferenceObject $running
InputObject SideIndicator
----------- -------------
sshd =>
redis <=
cron <=
<= means "only in the reference" (missing), => "only in the
difference" (unexpected). Add -IncludeEqual to see matches too.
Compare objects by property with -Property:
$before = @(
[pscustomobject]@{ Name = 'app.exe'; Version = '1.2' }
[pscustomobject]@{ Name = 'lib.dll'; Version = '3.0' }
)
$after = @(
[pscustomobject]@{ Name = 'app.exe'; Version = '1.3' }
[pscustomobject]@{ Name = 'lib.dll'; Version = '3.0' }
)
Compare-Object $before $after -Property Name, Version |
Sort-Object Name, SideIndicator |
ForEach-Object { '{0} {1} {2}' -f $_.SideIndicator, $_.Name, $_.Version }
<= app.exe 1.2
=> app.exe 1.3
Group-Object
$orders = @(
[pscustomobject]@{ Customer = 'Ada'; Total = 120 }
[pscustomobject]@{ Customer = 'Linus'; Total = 45 }
[pscustomobject]@{ Customer = 'Ada'; Total = 80 }
[pscustomobject]@{ Customer = 'Grace'; Total = 300 }
[pscustomobject]@{ Customer = 'Linus'; Total = 55 }
)
$orders | Group-Object Customer | ForEach-Object {
[pscustomobject]@{
Customer = $_.Name
Orders = $_.Count
Spent = [int]($_.Group | Measure-Object Total -Sum).Sum
}
} | Sort-Object Spent -Descending
Customer Orders Spent
-------- ------ -----
Grace 1 300
Ada 2 200
Linus 2 100
Each group has Name, Count, and Group (the objects in it) — combine
with Measure-Object for per-group totals, like SQL's GROUP BY.
Fast lookups: -AsHashTable
$users = @(
[pscustomobject]@{ Id = 1; Name = 'Ada' }
[pscustomobject]@{ Id = 2; Name = 'Linus' }
)
$byId = $users | Group-Object Id -AsHashTable
$byId[2].Name
Linus
Build a lookup table once instead of searching a list with Where-Object
inside a loop — much faster for large data.