Запуск ForEach-Object -Parallel, данные отсутствуют при экспорте

#powershell #parallel-processing #microsoft-graph-api #office365

#powershell #параллельная обработка #microsoft-graph-api #office365

Вопрос:

У меня есть некоторый рабочий код, который в основном запрашивает 2 разные конечные точки Graph API, затем ищет совпадение в User Principal Name column , и вставляет extension_335d4df9847945fbaa472c8b8fbb5d75_employeeNumber столбец и значения в экспортированный csv (спасибо пользователю @PMental за это решение) Этот столбец является производным от атрибута, который был недавно расширен из нашего локального AD.

Этот код работает отлично, однако, если я попытаюсь его распараллелить, я не получу результатов в extension_335d4df9847945fbaa472c8b8fbb5d75_employeeNumber столбце.

Это потому, что после распараллеливания я не могу обмениваться переменными между параллельными процессами? Если да, то как мне это сделать?

Приведенный ниже код — если вы удалите -Parallel, он работает нормально:

 $graphApiUri = "https://graph.microsoft.com/v1.0/reports/getOffice365ActiveUserDetail(period='D90')"

$Uri = "https://graph.microsoft.com/v1.0/users?`$select=userPrincipalName,extension_335d4df9847945fbaa472c8b8fbb5d75_employeeNumber"

$O365Report = Invoke-RestMethod -Method Get -Uri $graphApiUri -Headers $headerParams | ConvertFrom-Csv

# If the result is more than 999, we need to read the @odata.nextLink to show more than one side of users
$UserDetails = while (-not [string]::IsNullOrEmpty($uri)) {
    # API Call
    $apiCall = try {
        Invoke-RestMethod -Headers $headerParams -Uri $uri -Method Get
    }
    catch {
        $errorMessage = $_.ErrorDetails.Message | ConvertFrom-Json
    }
    $uri = $null
    if ($apiCall) {
        # Check if any data is left
        $uri = $apiCall.'@odata.nextLink'
        $apiCall
    }
}

Write-Output "Matching UPN to employeeNumber..."

$O365Report | ForEach-Object -Parallel {
    $CurrentEmpNumber = $UserDetails.value |
        Where-Object userPrincipalName -eq $_.'User Principal Name' |
            Select-Object -ExpandProperty extension_335d4df9847945fbaa472c8b8fbb5d75_employeeNumber -ErrorAction SilentlyContinue
    $_ | Add-Member -MemberType NoteProperty -Name extension_335d4df9847945fbaa472c8b8fbb5d75_employeeNumber -Value $CurrentEmpNumber
}

$O365Report | Export-Csv $ReportCSV -NoTypeInformation
Write-Output "Report saved to $ReportCSV."
 

Комментарии:

1. Это не похоже на хорошее соответствие для параллельной обработки, поскольку вы просто локально просматриваете массивы в поисках совпадений. Если у вас не было результатов 500K и время не имело значения, ИМХО, это не имеет смысла. Теперь, если вам нужно было выполнить еще один вызов rest для каждого пользователя, возможно, стоит приложить усилия для этого.

2. Я ценю вашу проницательность! Спасибо

Ответ №1:

Когда вы находитесь внутри ForEach-Object -Parallel блока сценария и пытаетесь ссылаться на переменные, которые были созданы вне его, вам нужно предварить имя переменной using: , чтобы оно было $using:UserDetails

Примеры:

Ничего не возвращает, поскольку $test недоступен в пределах блока параллельного скрипта:

 $test = 1;
0..5 | % -Parallel { $test; };
 

Возвращает значение $test в пять раз, потому что с помощью $using:test теперь вы можете видеть его значение:

 $test = 1;
0..5 | % -Parallel { $using:test; };
 

Из документации:

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/foreach-object?view=powershell-7.1

Набор параметров ForEach-Object -Parallel запускает блоки сценариев параллельно в отдельных потоках процесса. Ключевое слово $using: позволяет передавать ссылки на переменные из потока вызова командлета в каждый поток запущенного блока сценария. Поскольку блоки сценария выполняются в разных потоках, переменные объекта, передаваемые по ссылке, должны использоваться безопасно. Как правило, безопасно читать из объектов, на которые ссылаются, которые не меняются. Но если состояние объекта изменяется, вы должны использовать потокобезопасные объекты, такие как .Net System.Коллекция.Параллельные типы (см. Пример 11).


Личное замечание:

Я бы также рекомендовал использовать -ThrottleLimit для ограничения его максимальных степеней параллелизма. Значение по умолчанию равно 5, но в зависимости от тестирования может потребоваться больше или меньше.

Комментарии:

1. Спасибо. С другой стороны, вы случайно не знаете, поддерживается ли функция -Parallel в Azure runbook?

2. @jpbcx43 понятия не имею, извините.