Я пытаюсь сравнить два многомерных массива в PowerShell. В каждом массиве много тысяч элементов - вот небольшой пример. В одном массиве у меня есть:
$arrOne
Username                        LocalOffice
john.doe@domain.com             US-California
need.help@domain.com            IT-Naples
another.example@domain.com      TR-Istanbul
(etc...)
В другом массиве у меня есть:
$arrTwo
Username                        Location
john.doe@domain.com             US
need.help@domain.com            US
another.example@domain.com      TR
(etc...)
Что мне нужно сделать, так это сравнить LocalOffice, связанный с каждым именем пользователя из $ arrOne, с первыми двумя символами Location, используя совпадающее имя пользователя в $ arrTwo (если оно существует). Если LocalOffice и Location не совпадают, выполните некоторые действия. Мой пример кода выглядит следующим образом:
$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
                }
            }
    }
}
При использовании стандартного вложенного ForEach (см. Выше) обработка этих массивов занимает некоторое время, поскольку каждый массив большой (и это будет частью сценария, который выполняется каждые 30 минут) и чувствителен ко времени. Чтобы надеяться найти мой ответ, у меня есть несколько вопросов по поводу вышеупомянутого:
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?
Спасибо
ОБНОВЛЕНИЕ:
Мы используем этот сценарий для управления нашими локальными объектами Active Directory и MSOL (Microsoft Online - Office 365). Мы используем DirSync для синхронизации AD с Office 365. Хотя в приведенных выше примерах имена изменены для удобства чтения, это основные команды, используемые для сбора данных массива:
[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
Массивы имеют разные размеры (arrTwo буквально в 10 раз больше размера arrOne). Нет гарантии, что объект из arrOne будет существовать в arrTwo.
Я пробовал еще несколько вещей, чтобы решить эту проблему с момента моей первоначальной публикации (особенно с помощью BREAK для выхода из второго цикла). После первоначальной публикации я понял, что могу добиться лучшего улучшения производительности, если смогу «вырваться» из второго цикла ForEach-Object, когда совпадение найдено. Одна вещь, которая замедляет процесс, заключается в том, что PowerShell продолжает проходить через arrTwo даже после того, как совпадение найдено. Я попытался добавить разрыв после того, как совпадение найдено, но я не могу заставить его выйти из цикла arrTwo и вернуться к следующему объекту в коллекции arrOne. Он продолжает ломать (заканчивать) весь скрипт.
    $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
            }
    }
Я пробовал разбить, разбить / продолжить, разбить / пометить, используя foreach вместо foreach-object, do / while и некоторые другие. Пока не повезло
Дополнительный вопрос:
4)  Can break be used to exit a ForEach-Object loop and return it to the “parent”
ForEach-Object?
еще раз спасибо
