Using some PowerShell kung-fu, you can easily compare arrays of all kinds of objects. There are many different scenarios you may find yourself in so let's dig in and see the ways we can build PowerShell to compare arrays.

To determine the best way to compare arrays, you must first figure out what types of elements are in both arrays.

  • Do both arrays contains all of the same type of object?
  • Do both arrays have the same number of elements?
  • Are there different types of objects in each array?

You must know the answer to each of these questions before you can accurate compare arrays. Let's cover each scenario.

Comparing Arrays of Strings

One of the easiest ways to compare arrays with PowerShell is if you have two arrays only containing strings. When you find yourself in this position, you've got a few different ways to compare strings in the arrays.

Using the -Contains or -In Operators

The -contains operator is a PowerShell operator that allows you to check to see if an object is in a collection. The -contains operator natively doesn't understand collections but y0u can build code to make it do your bidding.

Let's say a collection (array) contains four strings like below.

$array = @('blue','red','purple','pink')

The -contains operator works by checking if a single string is in that array like this:

$array -contains 'pink'

When the collection on the left contains that string, PowerShell will return True. If not, it will return False.

PowerShell -contains Operator

We can compare arrays using the -contains operator by reading each string in an array and checking to see if the other array contains that string.

Let's say I want to compare two arrays to see which strings in the first array exist in the second array.

$array = @('blue','red','purple','pink')
$array2 = @('brown','red','black','yellow')

$array | ForEach-Object {
    if ($array2 -contains $_) {
        Write-Host "`$array2 contains the `$array1 string [$_]"
    }
}

You could alternatively use the -in operator which is identical to the -contains operator yet the syntax is opposite. When using the -contains operator, the array is defined on the left side. Using the -in operator, the array is defined on the right side like below:

$array | ForEach-Object {
    if ($_ -in $array2) {
        Write-Host "`$array2 contains the `$array1 string [$_]"
    }
}

Using Where-Object

Alternatively, you could also use the Where-Object cmdlet to return all strings in one array in the other like below.

$array | Where-Object -FilterScript { $_ -in $array2 }

Using the Compare-Object Cmdlet

You can also use PowerShell to compare arrays using the Compare-Object cmdlet. This cmdlet takes a reference object and a difference object and returns a side indicator indicating which elements are and are not in either array.

Compare-Object -ReferenceObject $array -DifferenceObject $array2
Using Compare-Object

You can see below that the Compare-Object cmdlet allows you to compare both arrays at once. If the SideIndicator property is =>, this means the InputObject property returned is in the DifferenceObject value and not in the ReferenceObject value and vice versa for the <= SideIndicator.

By default, Compare-Object returns differences. You can also return all of the strings in each array that are in both by using the IncludeEqual parameter.

Comparing arrays with Compare-Object

Comparings Arrays of Complex Objects

Simple enough, right? Now, let's bring objects into the mix. Let's say we've got a field in this HR database of ours and we'd like to populate this into the Active Directory description field. Prior to doing this, we first have to have a common identifier. In my environment, there's an employee number both in the HR database and in the custom Active Directory attribute. So let's attempt to match this.

First, let's see what happens if we try our previous approach. Here's the CSV file we're using.

poweshell


Here's how I get our two datasets.

$ad_users = Get-AdUser -Filter {enabled -eq $true} -Properties employeeNumber | select employeenumber,samaccountname,description
$users_from_database = Import-Csv 'database_users.csv' | select employee number

What happens when we run these two arrays through the same scenario as our strings? �Absolutely nothing. Why?

The reason is because you can't typically say $object1 -eq $object2 because objects are more complex than a simple string, boolean or integer. There are some other circumstances where this isn't the case but I try to make it a habit to compare object properties; not entire objects. So in this instance, we have to do something like this:

$ad_user[0].employeeNumber -eq $users_from_database[0].employeeNumber

What's the solution? Currently, I've got two solutions. When dealing with thousands of objects it's not quick but it works. I'd like to know if anyone else has any other suggestions.

$ad_employee_numbers = $ad_users | % {$_.employeenumber}

## Create an array of strings of only the AD user's employee number
$users_from_database | Where-Object -FilterScript { $ad_employee_numbers -contains $_.employeeNumber }

We can also use Compare-Object although this is slower.

$ad_employee_numbers = $ad_users | ForEach-Object {$_.employeenumber}

## Create an array of strings of only the AD user's employee number
$database_user_employee_numbers = $users_from_database | ForEach-Object {$_.employeenumber}

## Create an array of strings of only the database user's employee number
(Compare-Object $ad_employee_numbers $database_user_employee_numbers -IncludeEqual | Where-Object -FilterScript {$_.SideIndicator -eq '=='}).InputObject

Conclusion

There are many different ways to use PowerShell to compare arrays. Arrays can be complex and thoroughly understanding objects inside of the arrays will greatly help you compare them.

Join the Jar Tippers on Patreon

It takes a lot of time to write detailed blog posts like this one. In a single-income family, this blog is one way I depend on to keep the lights on. I'd be eternally grateful if you could become a Patreon patron today!

Become a Patron!