powershell - 运行 ForEach-Object -Parallel,导出数据丢失
问题描述
我有一些工作代码,基本上查询 2 个不同的 Graph API 端点,User Principal Name column
然后extension_335d4df9847945fbaa472c8b8fbb5d75_employeeNumber
在最近从我们的现场广告扩展。
这段代码工作得很好,但是如果我尝试并行化它,我在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."
解决方案
在脚本块内,并且您尝试引用在其外部创建的变量时,您需要ForEach-Object -Parallel
在变量名前加上using:
$using:UserDetails
例子:
不返回任何内容,因为$test
在并行脚本块的范围内无法访问:
$test = 1;
0..5 | % -Parallel { $test; };
返回$test
五次的值,因为通过使用$using:test
您现在可以看到它的值:
$test = 1;
0..5 | % -Parallel { $using:test; };
从文档:
ForEach-Object -Parallel 参数集在单独的进程线程上并行运行脚本块。$using: 关键字允许将变量引用从 cmdlet 调用线程传递到每个正在运行的脚本块线程。由于脚本块在不同的线程中运行,因此必须安全地使用通过引用传递的对象变量。一般来说,从不改变的引用对象中读取是安全的。但是如果正在修改对象状态,那么您必须使用线程安全对象,例如 .Net System.Collection.Concurrent 类型(参见示例 11)。
个人备注:
我还建议使用-ThrottleLimit
来限制其最大并行度。默认值为 5,但您可能需要更多或更少,具体取决于测试。
推荐阅读
- typescript - TS测试!如何在 TypeScript 中编写此 JS 代码?
- macos - Mac OS X Notarizing Application - 二进制文件的签名无效
- questdb - 如何以编程方式从 QuestDB 下载数据?
- html - 导航栏项目定位
- javascript - Twilio API | PHP/Symfony 中的实时回调状态
- javascript - 如何仅使用拖放 java 脚本上传文本文件
- node.js - 如何更改中间件 node.js 中的响应标头
- email - list-unsubscribe-post 如何工作以及电子邮件客户端是否等待 http post url 的响应
- powerbi - PowerBI - 并行自动更新问题
- java - Http 状态 500 - 内部服务器错误 Glassfish