Я оптимизировал свой код для повышения производительности, используя ForEach-Object -AsJob -Parallel ...
.
Однако у него есть серьезные недостатки: я не могу писать отладочные сообщения на консоль или отлаживать свой код, проходя через него.
Итак, каждый раз, когда я хочу отладить свой код, мне приходится удалить параметры -AsJob
и -Parallel
, а затем, например. добавьте операторы ведения журнала отладки, чего я хочу избежать (!). Я не понимаю, как это масштабируется - что, если бы у меня были сотни параллельных циклов для каждого цикла, которые выглядели бы как «черные ящики».
Как я могу писать отладочные сообщения на консоль и выполнять свой код при использовании ForEach-Object -AsJob -Parallel ...
?
$appPermissionsJob = $servicePrincipals | ForEach-Object -AsJob -ThrottleLimit $ThrottleLimit -Parallel {
$spApplicationPermissions = $using:spApplicationPermissions
$servicePrincipalId = $_.Id
try {
$applicationPermissions = Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $servicePrincipalId -All -PageSize 999
if ($applicationPermissions -ne $null) {
$applicationPermissions | ForEach-Object {
Write-Host "Processing service principal ${servicePrincipalId} with app role $($_.ResourceId)"
if ($_.ResourceId -eq $using:MSGraphServicePrincipalId) {
$item = New-Object PSObject -Property ([ordered] @{
ServicePrincipalId = $_
ApplicationPermissions = $applicationPermissions
})
$spApplicationPermissions.TryAdd($servicePrincipalId, $item)
}
}
}
}
catch {
Write-Verbose "Failed to download delegated permissions for service principal ${servicePrincipalId}: $($_.Exception.Message)"
$dictFailed.TryAdd($servicePrincipalId, $_.Exception.Message)
}
}
После запуска введите скрипт: $applicationPermissions и $applicationPermissions.Count, чтобы проверить, есть ли какие-либо данные. Хост записи должен возвращать данные. Скорее всего, $applicationPermission не имеет нулевого значения, но не содержит перечисляемого массива. поэтому код не проходит через foreach.
Кстати: вы говорите об отладочных сообщениях, тогда как используете Write-Verbose . PowerShell имеет отдельные потоки вывода для отладочных и подробных сообщений, причем сообщения отладки создаются с помощью Write-Debug. Тем не менее, рассматриваемая проблема относится к обоим этим потокам.
@jdweng - это не имеет особого смысла. $applicationPermissions
не $null
и содержит данные
Как правило, командлеты, которые принимают блоки сценариев , ожидают, что эти блоки сценариев будут сами управлять выводом своего потока, а вызывающему объекту необходимо использовать перенаправления для захвата или подавления такого вывода.
Таким образом, если вывод заданного потока , такого как подробный поток в рассматриваемом случае, не включен внутри блока сценария, он не будет отображаться в контексте вызывающего объекта.
Следовательно, чтобы отобразить вывод подробного потока, вы должны либо использовать вызовы Write-Verbose -Verbose ...
внутри блока скрипта (т. е. используя общий параметр -Verbose
), либо установить $VerbosePreference = 'Continue'
в начале блока.
Однако из-за предполагаемой ошибки, начиная с PowerShell (Core) 7.4.x, вывод из параллелизма на основе потоков - как через ForEach-Object -Parallel (с -AsJob
или без него), так и Start-ThreadJob - неожиданно дополнительно фильтруется настройками управления потоком вызывающей стороны (с помощью общих параметров или эквивалентных переменных предпочтений).
Вот минимальные примеры, которые обеспечивают обходной путь:
# !! The *outer* -Verbose arguably shouldn't be necessary in either case,
# !! but is, as of PowerShell 7.4.x
ForEach-Object -Parallel { Write-Verbose hi -Verbose } -Verbose
ForEach-Object -AsJob -Parallel { Write-Verbose hi -Verbose } |
Receive-Job -Wait -AutoRemoveJob -Verbose
Спасибо, @mklement0. Вы говорите, что вызывающему абоненту необходимо использовать перенаправления для захвата или подавления такого вывода, но вы не используете перенаправления внутри своего кода?
Вам нужно, как я могу отладить этот код, т. е. пройти через него, как в других языках программирования?
Есть ли преимущество использования Receive-Job
перед Wait-Job
? Зачем это нужно -AutoRemoveJob
?
@Shuzheng: Перенаправления: это была общая информация, которая не применима к вашему варианту использования, учитывая, что (а) вы просто хотите распечатать информацию на дисплее и (б) перенаправления в целом применяются только к фактическому выводу потока, тогда как ваша проблема в его отсутствии из-за того, что вы не включили подробный поток в источнике.
@Shuzheng: Wait-Job
просто ждет завершения задания, не получая (собирая) его выходные данные. Receive-Job
, напротив, собирает выходные данные по умолчанию асинхронно; если вы добавите -Wait
, сначала ожидается завершение задания, а -AutoRemoveJob
после этого автоматически удаляет задание. Этот метод полезен для автономных фрагментов кода, демонстрирующих, что выводит данное задание.
Спасибо за помощь! Я создам новый вопрос, если вы настаиваете и верите, что у вас есть ответ :)
С удовольствием, @Shuzheng; Я не осознавал, что вы с самого начала явно спрашивали об отладке, поэтому в конце концов нет необходимости создавать новый вопрос. Я скоро обновлю этот ответ, но, боюсь, новости не очень хорошие.
Убедитесь, что настройка подробного вывода не подавляет подробный вывод изнутри параллельного блока, тогда
... |Receive-Job -Verbose