Using Compare-Object in PowerShell

Sometimes, you have to compare specific values in your PowerShell output, and although you can stare at your screen to do that… You can also use Compare-Object. In this blog post, I will show you how it works and how it makes things a lot easier 🙂

What is Compare-Object?

“The Compare-Object cmdlet compares two sets of objects. One set of objects is the reference, and the other set of objects is the difference.

Compare-Object checks for available methods of comparing a whole object. If it can’t find a suitable method, it calls the ToString() methods of the input objects and compares the string results. You can provide one or more properties to be used for comparison. When properties are provided, the cmdlet compares the values of those properties only.”

Source: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/compare-object?view=powershell-7.4

Aliases

These are two aliases for Compare-Object that might be familiar to you:

  • Compare
  • Diff

But, as always, only use alias in the command line and not in scripts 🙂 #Readability

Parameters

Compare-Object has a set of Parameters which you can use:

CaseSensitive

Using this parameter makes it possible to switch to case sensitivity while comparing objects; PowerShell isn’t case-sensitive by default, allowing values to be checked based on case sensitivity.

Culture

You can use this to specify the culture, and it might be that the source object is in another culture than the destination object. Values are the ones you can retrieve from running, for example, nl-NL or en-US

[System.Globalization.CultureInfo]::GetCultures([System.Globalization.CultureTypes]::AllCultures).Name

DifferenceObject

This is the Parameter to specify the object that will be compared against the RefenceObject.

ExcludeDifferent

You can use this Parameter to show only the equal values instead of the different values.

IncludeEqual

The matches between the ReferenceObject and the DifferenceObject will be shown using this Parameter.

PassThru

When using this Parameter, Compare-Object omits the PSCustomObject wrapper around the compared object and will return unchanged objects.

Property

You can use this to specify an array of properties of the ReferenceObject and DifferenceObject instead of comparing all properties.

ReferenceObject

This Parameter will specify the array as the reference for comparing it with the DifferenceObject.

SyncWindow

This Parameter will specify the adjacent objects that Compare-Object inspects while checking for matches. This will speed up the process if Compare-Object doesn’t find the object in the same position inside a collection. However, using this might be less accurate!

Examples

Comparing values in a text file

In the example below, I compare the contents of two text files called a.txt and b.txt:

You can see the SideIndicator with an arrow indicator. => tells you that the value is only in the DifferenceObject, <= will indicate that the value is only in the ReferenceObject. If the IncludeEqual Parameter is used, == will suggest that the value exists in the ReferenceObject and the DifferenceObject.

Comparing simple objects

You can also compare simple objects like this:

This compares both strings (12345 and 67890) on the property Length. Both are 5 in Length, so the == SideIndactor is returned (Equal)

Comparing complex objects

You can also compare more complex objects; in the example below, I created a $before containing all the files of my Scripts folder. I then added “Test” to b.txt and stored all the files in $after. Comparing those two showed that the file was changed by the LastWriteTime object.

Output in a more readable format

The examples above are excellent for checking things that are changed, but you can make the output more readable by selecting more Properties and creating a PSCustomObject. For example, this script will output the same as above but more readable:

The script:

$before = Get-ChildItem
"test" | Out-File .\b.txt -Append
$after = Get-ChildItem
$compare = Compare-Object -ReferenceObject $before -DifferenceObject $after -Property Name, CreationTime, LastWriteTime
if ($null -ne $compare) {
    $differencetotal = foreach ($change in $compare) {
        if ($change.SideIndicator -match ">") {
            $action = 'Added'
        }
        if ($change.SideIndicator -match "<") {
            $action = 'Removed'
        }

        if ($change.SideIndicator -eq "==") {
            $action = 'Not changed'
        }

        [PSCustomObject]@{
            Name          = $change.name
            CreationTime  = $change.CreationTime
            LastWriteTime = $change.LastWriteTime
            Action        = $action
        }
    }
}

$differencetotal

Wrapping up

In the blog post, I showed how to use Compare-Object to check and report differences between objects; some scripts take it a few steps further, making it easier to check all objects instead of specifying them all beforehand. For example, check out this article from Jeffery Hicks https://jdhitsolutions.com/blog/powershell/8196/comparing-powershell-property-names/.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.