Powershell – Comparing array variables in PowerShell


I have this script to compare two folders.

$firstfolder = Get-ChildItem C:\firstfolder
$secondfolder = Get-ChildItem C:\firstfolder

if ($firstfolder -eq $secondfolder) {
Write-Host "Folders are the same."
} else {
    Write-Host "Error: Doesn't match."

As you can see, I compare the same folder. Problem is, that it will never consider, that the arrays are equal. Why?

Best Solution

In PowerShell, variables that point to arrays are evaluated in expressions by enumerating the contents of the arrays themselves.

For example this expression:

$firstFolder | Get-Member

will return information about the System.IO.DirectoryInfo type, which indeed is the type of the first element in the $firstFolder array. If you want to operate on the array object itself, you have to explicitly tell PowerShell to treat the object as array by using the , operator. The following expression:

,$firstFolder | Get-Member

will expectedly return information about System.Object[].

However, when the -eq operator is used between two array variables, things are a bit different. PowerShell will, in fact, enumerate only the array on the left side and compare each item to the array on the right side as a whole. The result will be an array of matching items or nothing at all when there are no matches. For example:

$a = 1..5
$b = 1..5
$a -eq $b         # returns zero-length array
[bool]($a -eq $b) # returns $false
$a -eq 3          # returns 3

In your particular case, the result will be zero-length array (or $false if casted to a boolean) since the $firstFolder array contains System.IO.DirectoryInfo objects that don't quite match the array in the $secondFolder variable.

What you really want is to compare the contents of both arrays against each other. This is where the Compare-Object cmdlet comes in handy:

Compare-Object $firstFolder $secondFolder -SyncWindow 0

This will return an array of differences between the two arrays or $null when the arrays are equal. More precisely, the resulting array will contain an object for each item that exists only in one array and not the other. The -SyncWindow 0 argument will make the order in which the items appear in the arrays count as a difference.

If all you need is a simple way to tell whether the two arrays are different without going into the details of what is different, you can simply check the length of the array returned by Compare-Object:

$areEqual = @(Compare-Object $firstFolder $secondFolder -SyncWindow 0).Length -eq 0

Notice how I explicitly told PowerShell to always package the results into an array, since Compare-Object may return $null when the arrays don't contain any differences.