我利用
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)
}
}
通常,接受脚本块的 cmdlet 期望这些脚本块能够控制其流输出本身,调用者需要使用重定向才能捕获或抑制此类输出。
因此,除非给定流的输出(例如本例中的verbose流),在脚本块内打开,否则它不会在调用者的上下文中出现 .
Write-Verbose -Verbose ...
调用(即使用通用
-Verbose
参数),或者在块的开头设置
$VerbosePreference = 'Continue'
。
假定的 bug,从 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