为什么PowerShell多线程场景下条件语句未正确执行?
问题原因
PowerShell的Runspace是相互隔离的独立运行环境,父作用域中定义的$extensionList变量不会自动传递到子Runspace执行的ScriptBlock内部,因此ScriptBlock执行时$extensionList为空值,-contains判断永远返回$false,这就是单线程正常、多线程异常的核心原因,和条件语句本身语法无关。
修复方案
- 将需要用到的
$extensionList作为额外参数传入ScriptBlock - 附加优化:统一扩展名大小写后再比较,避免不同文件名大小写导致的匹配遗漏
修正后的完整代码
$extensionList = @(".DLL",".EXE") $systemDir = "C:\Windows\System32\" $threadNumber = 4 #threads $tempList = @() $ScriptBlock = { Param ($tmpFilePath, $extensionList) # 新增参数接收扩展名列表 $tmpExtension = [IO.Path]::GetExtension($tmpFilePath).ToUpper() # 统一转大写避免匹配问题 if ($extensionList -contains $tmpExtension) { Return $tmpFilePath } Return $null } $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, $threadNumber) $RunspacePool.Open() $Jobs = @() $tmpfileNameList = (Get-ChildItem -Path $systemDir -File) | select-object Name foreach($tmpfileName in $tmpfileNameList) { $tmpFilePath = $systemDir + $tmpfileName.Name # 传入两个参数:文件路径、扩展名列表 $Job = [powershell]::Create().AddScript($ScriptBlock).AddArgument($tmpFilePath).AddArgument($extensionList) $Job.RunspacePool = $RunspacePool $Jobs += New-Object PSObject -Property @{ Pipe = $Job Result = $Job.BeginInvoke() } } while ($Jobs.IsCompleted -contains $false) {Start-Sleep -Milliseconds 100} $Results = @() ForEach ($Job in $Jobs){ $result = $Job.Pipe.EndInvoke($Job.Result) if ($result -ne $null) { $tempList += $result } } foreach($tmp in $tempList) { Write-Host $tmp }
额外优化建议
- 可以在调用
Get-ChildItem时直接过滤扩展名,减少无意义的多线程任务开销:Get-ChildItem -Path $systemDir -File -Include *.dll,*.exe,这样后续不需要再做扩展名判断,能大幅提升执行效率 - 64位系统下如果使用32位版本的PowerShell执行代码,会自动将
C:\Windows\System32重定向到C:\Windows\SysWOW64,如果需要访问64位System32目录,请使用64位PowerShell运行
内容的提问来源于stack exchange,提问作者dinnershow
相关产品推荐
相关产品推荐

