如何在PowerShell中以Job方式并行运行多服务器文件哈希校验脚本
实现方案
核心优化思路
- 源文件SHA256全局预计算一次,无需每台服务器重复计算,减少不必要的性能消耗
- 所有并行任务仅返回校验结果对象,不直接操作日志文件,从根源避免并行写入错乱
- 全部任务执行完成后,统一对结果集进行排序、导出操作
实现代码
版本1:兼容PowerShell 5.1(Start-Job实现)
# 预加载配置 $Modulos = Get-Content -Path .\mod.txt | Sort-Object -Unique $Orig = "H:\Redsys_Client" $Machines = Get-Content -Path .\servers.txt | Sort-Object -Unique $logPath = ".\test.csv" # 预计算所有源文件哈希,仅执行1次,避免重复计算 $sourceHashes = @{} foreach ($name in $Modulos) { $srcPath = Join-Path $Orig "$name\$name.exe" if (Test-Path -Path $srcPath) { $sourceHashes[$name] = [PSCustomObject]@{ Hash = (Get-FileHash -Path $srcPath -Algorithm SHA256).Hash Path = $srcPath } } } # 批量提交并行任务 $jobs = foreach ($Server in $Machines) { Start-Job -ArgumentList $Server, $Modulos, $sourceHashes -ScriptBlock { param($Server, $Modulos, $sourceHashes) $results = @() foreach ($name in $Modulos) { # 跳过不存在的源文件记录 if (-not $sourceHashes.ContainsKey($name)) { continue } $destPath = "\\$Server\Redsys\$name\$name.exe" $resultObj = [PSCustomObject]@{ Algor_Orig = "SHA256" Hash_Orig = $sourceHashes[$name].Hash Orig_Path = $sourceHashes[$name].Path Algor_Dest = "SHA256" Hash_Dest = $null Dest_Path = $destPath Result = "PATH_NOT_EXIST" } if (Test-Path -Path $destPath) { $destHash = (Get-FileHash -Path $destPath -Algorithm SHA256).Hash $resultObj.Hash_Dest = $destHash $resultObj.Result = if ($destHash -eq $sourceHashes[$name].Hash) { "EQUAL" } else { "NOT_EQUAL" } } $results += $resultObj } return $results } } # 等待所有任务完成,接收结果 $allResults = $jobs | Wait-Job | Receive-Job # 清理已完成的job $jobs | Remove-Job # 统一导出结果到CSV,使用分号分隔匹配原格式 $allResults | Export-Csv -Path $logPath -Delimiter ';' -NoTypeInformation -Encoding UTF8
版本2:PowerShell 7+ 高性能实现(ForEach-Object -Parallel)
比Start-Job资源占用更低、执行速度更快,适合PowerShell 7及以上环境使用
# 预加载配置 $Modulos = Get-Content -Path .\mod.txt | Sort-Object -Unique $Orig = "H:\Redsys_Client" $Machines = Get-Content -Path .\servers.txt | Sort-Object -Unique $logPath = ".\test.csv" # 预计算所有源文件哈希,仅执行1次,避免重复计算 $sourceHashes = @{} foreach ($name in $Modulos) { $srcPath = Join-Path $Orig "$name\$name.exe" if (Test-Path -Path $srcPath) { $sourceHashes[$name] = [PSCustomObject]@{ Hash = (Get-FileHash -Path $srcPath -Algorithm SHA256).Hash Path = $srcPath } } } # 并行执行校验,ThrottleLimit控制并行数,可根据实际情况调整 $allResults = $Machines | ForEach-Object -Parallel { $Modulos = $using:Modulos $sourceHashes = $using:sourceHashes $Server = $_ $results = @() foreach ($name in $Modulos) { if (-not $sourceHashes.ContainsKey($name)) { continue } $destPath = "\\$Server\Redsys\$name\$name.exe" $resultObj = [PSCustomObject]@{ Algor_Orig = "SHA256" Hash_Orig = $sourceHashes[$name].Hash Orig_Path = $sourceHashes[$name].Path Algor_Dest = "SHA256" Hash_Dest = $null Dest_Path = $destPath Result = "PATH_NOT_EXIST" } if (Test-Path -Path $destPath) { $destHash = (Get-FileHash -Path $destPath -Algorithm SHA256).Hash $resultObj.Hash_Dest = $destHash $resultObj.Result = if ($destHash -eq $sourceHashes[$name].Hash) { "EQUAL" } else { "NOT_EQUAL" } } $results += $resultObj } return $results } -ThrottleLimit 10 # 统一导出结果到CSV $allResults | Export-Csv -Path $logPath -Delimiter ';' -NoTypeInformation -Encoding UTF8
注意事项
- ThrottleLimit参数可根据本地网络带宽和服务器负载调整,建议设置为10~30之间,避免请求过多导致远程服务器拒绝访问
- 若远程共享需要身份验证,可提前用
New-PSDrive建立共享连接后再执行脚本 - 导出的CSV默认使用UTF8编码,若需要兼容旧版Excel可调整编码参数为
Default
内容的提问来源于stack exchange,提问作者Vittor de Castro
相关产品推荐
相关产品推荐

