PowerShell Compare-Object: Compare Files, Folders, CSV and Objects

PowerShell Compare-Object takes two sets of objects and tells you which items exist on only one side. Give it a reference set and a difference set, and it returns the mismatches with an arrow showing where each one came from:

Compare-Object -ReferenceObject $before -DifferenceObject $after

I use it constantly for audits: two server lists, two folders, last month’s staff export against this month’s. Below are the parameters that matter, real output from PowerShell 7 and Windows PowerShell 5.1, and the spots where the two versions disagree.

How Compare-Object works: reference, difference and SideIndicator

Here’s a field office list compared with the offices that show up in payroll. The first array is the reference, and the second is the difference:

$fieldOffices = 'Austin', 'Denver', 'Seattle', 'Boston'
$payrollList  = 'Austin', 'Denver', 'Chicago', 'Seattle'

Compare-Object -ReferenceObject $fieldOffices -DifferenceObject $payrollList

Output:

InputObject SideIndicator
----------- -------------
Chicago     =>
Boston      <=

The output wraps each mismatch in an object with two properties. InputObject is the value, and SideIndicator says which side it lives on:

SideIndicatorMeaning
<=Only in the reference object (first set)
=>Only in the difference object (second set)
==In both sets (shown only with -IncludeEqual)

Items found in both lists are hidden by default. The two parameters are positional, so Compare-Object $a $b works too. On Windows you can also type the aliases compare or diff.

For more ways to match up two lists, including -contains and loops, see comparing two arrays for matches.

Show matching items with -IncludeEqual

Add -IncludeEqual when you want the full picture. The matches come back with ==, followed by the differences:

$fieldOffices = 'Austin', 'Denver', 'Seattle', 'Boston'
$payrollList  = 'Austin', 'Denver', 'Chicago', 'Seattle'

Compare-Object $fieldOffices $payrollList -IncludeEqual

Output:

InputObject SideIndicator
----------- -------------
Austin      ==
Denver      ==
Seattle     ==
Chicago     =>
Boston      <=

To check a single value instead of a whole list, the -contains operator on an array is simpler and faster.

-ExcludeDifferent: PowerShell 7 vs Windows PowerShell 5.1

-ExcludeDifferent throws away the mismatches and keeps only what’s common to both sets. This is where the two shells behave differently, so I ran the same script in each:

$fieldOffices = 'Austin', 'Denver', 'Seattle', 'Boston'
$payrollList  = 'Austin', 'Denver', 'Chicago', 'Seattle'

"PowerShell $($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)"
'--- -ExcludeDifferent'
Compare-Object $fieldOffices $payrollList -ExcludeDifferent
'--- -ExcludeDifferent -IncludeEqual'
Compare-Object $fieldOffices $payrollList -ExcludeDifferent -IncludeEqual

Output:

PowerShell 7.6
--- -ExcludeDifferent

InputObject SideIndicator
----------- -------------
Austin      ==
Denver      ==
Seattle     ==
--- -ExcludeDifferent -IncludeEqual
Austin      ==
Denver      ==
Seattle     ==
PowerShell Compare-Object -ExcludeDifferent output in PowerShell 7
-ExcludeDifferent alone returns the three matching offices (PowerShell 7)

Since PowerShell 7.1, -ExcludeDifferent turns on -IncludeEqual for you, so both commands print the three shared offices. Windows PowerShell 5.1 returns nothing for the first command: