user1678436
user1678436

Reputation: 43

Powershell - Comparing two arrays returns wrong result

I was hoping someone would be able to help with a problem I've been running into comparing arrays.

Here's some background. I have a powershell script that generates a list of domain controllers, checks to see if they are online and then writes the data to a csv file. This works fine.

I want to run this weekly and send an alert if any domain controllers are added or removed.

I have another script that imports the previously generated CSV to an array, then I generate a new list of domain controllers and send that list to a new array. I am attempting to compare the two using compare-object, and export a new CSV with a list of differences.

However, I'm testing this by manually modifying the old CSV, and I've found that no matter which domain controller I remove from the previous list or where I add a new one, it always reports that the change is the last domain controller on the list.

For example, here's what my CSV file looks like:

"DC_Name","Ping_Response"
"dc1.testcompany.com","online"
"dc2.testcompany.com","online"
"dc3.testcompany.com","online"
"dc4.testcompany.com","online"

If I test this by deleting "dc3.testcompany.com","online" and running the script again, it knows that the list has changed, but it reports that the new entry is "dc4.testcompany.com","online" and not "dc3.testcompany.com","online".

Similarly, if I modify my old csv to look like this:

"DC_Name","Ping_Response"
"dc1.testcompany.com","online"
"dc2.testcompany.com","online"
"dc5.testcompany.com","online"
"dc3.testcompany.com","online"
"dc4.testcompany.com","online"

it will report that the one that is different from the new list is "dc4.testcompany.com","online", not the one I've added in the middle.

I must be doing something wrong with my comparison. Here is relevant part of the script I'm using:

$newDCArray = @(Import-CSV DC_List.csv)

$oldDCArray = @(Import-CSV Last_DC_List.csv)

$diff = Compare-Object $oldDCArray $newDCArray

if($diff -eq $null)
    {
    Write-Host "No changes to DCs"
    }
else    
    {
    Write-Host "There have been changes to DCs"
    $diff| Export-CSV DC_Change_List.csv -notypeinformation
    Send-MailMessage –From "[email protected]" –To "[email protected]" –Subject "Alert - Domain Controllers Added or Removed" –Body "DC Report Attached" –SmtpServer "smtp.xxxxxxxxxxx.net" -Attachments "DC_Change_List.csv"
    }

Please let me know if anyone has any ideas!

Thank you! John

Upvotes: 4

Views: 3376

Answers (2)

davidhigh
davidhigh

Reputation: 15518

Here is a version of the accepted answer which determines the properties automatically:

$newDCArray = Import-CSV DC_List.csv
$oldDCArray = Import-CSV Last_DC_List.csv

$propNew = ($newDCArray | Get-Member | ?{$_.MemberType -eq "NoteProperty" | Select -expand Name})
$propOld = ($oldDCArray | Get-Member | ?{$_.MemberType -eq "NoteProperty" | Select -expand Name})
$prop = ($propNew + $propOld) | Get-Unique

$diff = Compare-Object $oldDCArray $newDCArray -Property $prop

Note that Get-Unique stuff, which performs a distinct union, is only relevant when the columns of the csv-File differ. Otherwise, you can use the properties of either one of the objects.

Upvotes: 0

latkin
latkin

Reputation: 16812

The objects returned by Import-Csv are not "real" objects which you should be doing comparisons with. They are dynamically-generated custom objects. You will notice that if you do an explicit check of $newDCArray[0] -eq $oldDCArray[0], it will return $false. Since the proper plumbing to check for equality is simply not present, Compare-Object has no hope of working correctly.

That's ok, though. Compare-Object has a -Property parameter which allows you to look at 1 or more specific properties of the given objects. The properties are real objects (strings), so the comparison works. In your case you are interested in 2 properties - DC_Name and Ping_Response, since you want to know if a server is new/deleted, as well as if a known server has gone offline.

This should work for you:

Compare-Object $oldDCArray $newDCArray -Property 'DC_Name','Ping_Response'

Also, make sure that -SyncWindow is sufficiently large such that the comparison is accurate. Or it is sometimes easiest to simply sort the arrays before comparison so you don't need to worry about that.

Upvotes: 4

Related Questions