I am trying to compare two multi-dimensional arrays in PowerShell. Each array has many thousands of elements – a small example follows. In one array I have:
$arrOne
Username LocalOffice
john.doe@domain.com US-California
need.help@domain.com IT-Naples
another.example@domain.com TR-Istanbul
(etc...)
In the other array, I have:
$arrTwo
Username Location
john.doe@domain.com US
need.help@domain.com US
another.example@domain.com TR
(etc...)
What I need to do is to compare the LocalOffice associated with each Username from $arrOne with the first two characters of Location using the matching Username in $arrTwo (if it exists). If LocalOffice and Location don’t match then take some actions. My code sample is as follows:
$arrOne | ForEach-Object {
$strOneName = $_.Username
If ($_.LocalOffice.Length -ge 2)
{
$strOneLocalOffice = $_.LocalOffice.substring(0,2)
}
Else
{
$strOneLocalOffice = "US"
}
$arrTwo | ForEach-Object {
If ($_.Username -eq $strOneName -eq $True)
{
If ($_.Location -eq $strOneLocalOffice -ne $True)
{
## Take action here if they don't match
write-host $_.Username
}
}
}
}
With the standard nested ForEach (above), it takes some time to process these arrays because each array is large (and this will be part of a script that runs every 30 minutes) and is time sensitive. To hopefully find my answer, I have a few questions about the above:
1) Is there some other (quicker) method to get the desired results?
2) Do I have to use ForEach and loop through arrTwo until I find the matching
Username from arrOne or is there some other quicker method to jump right to the
matching Username in arrTwo?
3) Is there a way to quickly merge (join) these two arrays together so then I
can ForEach once through a single array and just compare individual objects
from the same element?
Thanks
UPDATE:
We use this script to help manage our local Active Directory and MSOL (Microsoft Online – Office 365) objects. We are using DirSync to keep sync our AD with Office 365. Although names are changed in the above examples for readability, these are the basic commands used to gather the array data:
[array]$arrOne = @(Get-ADObject -Filter {(objectClass -eq "User") -And (objectCategory -eq "Person")} -SearchBase “OU=Test,DC=domain,DC=com” -Properties UserPrincipalName,physicalDeliveryOfficeName) | Select-Object UserPrincipalName, physicalDeliveryOfficeName
[array]$arrTwo = @(Get-MsolUser -Synchronized -All) | Where-Object {$_.isLicensed -eq "True"} | Select-Object UserPrincipalName, UsageLocation
The arrays are different sizes (arrTwo is literally 10 times the size of arrOne). There is no guarantee that an object from arrOne will exist in arrTwo.
I’ve tried a few more things to solve this since my original posting (especially using BREAK to exit the second loop). After the original post, I realized I can get the best performance improvement if I can “break” out of the second ForEach-Object loop when a match is found. One thing that is slowing things down is that PowerShell keeps looping through arrTwo even after a match is found. I tried adding break after a match is found but I can’t get it to break out of the arrTwo loop and return to the next object in the arrOne collection. It keeps breaking (ending) the entire script.
$arrTwo | ForEach-Object {
If ($_.Username -eq $strOneName -eq $True)
{
If ($_.Location -eq $strOneLocalOffice -ne $True)
{
## Take action here if they don't match
write-host $_.Username
}
Break
}
}
I tried break, break/continue, break/label, using foreach instead of foreach-object, do/while and some others. No luck yet.
An additional question:
4) Can break be used to exit a ForEach-Object loop and return it to the “parent”
ForEach-Object?
Thanks again
Best Answer
Thank you all for your help - they helped to lead me to finding a solution to solve my problem and getting Break/Continue to work properly. Now the performance is more comparable. I had to change the inner loop ($arrTwo) from ForEach-Object to ForEach. That changed the method by which the loop is initiated.