Я пытаюсь сравнить два многомерных массива в 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?
еще раз спасибо