我正在尝试获取windows系统目录(C:\windows\System32(中的dll和exe文件名。
该路径中的文件太多,所以我尝试使用多线程。
然而,当比较(在"IF"语句中(由Addscript添加的ScriptBlock中的扩展时,只有"IF";"错误";结果出现,所以无法将文件名添加到列表中。
if ($extensionList -contains $tmpExtension.ToString())
也许条件语句是错误的,或者ScriptBlock是错误的?当不使用多线程时,条件语句正常工作。
整个代码(Powershell 5.1(:
$extensionList = @(".DLL",".EXE")
$systemDir = "C:WindowsSystem32"
$threadNumber = 4 #threads
$tempList = @()
$ScriptBlock = {
Param ($tmpFilePath)
$tmpExtension = [IO.Path]::GetExtension($tmpFilePath)
if ($extensionList -contains $tmpExtension.ToString()) {
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)
$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){
if ($Job.Pipe.EndInvoke($Job.Result) -ne $null) {
$tempList += $Job.Pipe.EndInvoke($Job.Result)
}
}
foreach($tmp in $tempList) {
Write-Host $tmp
}
主要问题是您的powershell
实例不知道$extensionList
是什么,因为它从未作为参数传递,因此它总是计算为:
$null -contains [IO.Path]::GetExtension($tmpFilePath)
如果您的意图是返回扩展名为.dll
或.exe
的文件的FullName
,那么您的scriptblock
应该是这样的:
$ScriptBlock = {
Param ($tmpFilePath, $extensionList)
if ($extensionList -contains [IO.Path]::GetExtension($tmpFilePath))
{
$tmpFilePath
}
}
foreach
循环看起来是这样的:
$tmpfileNameList = (Get-ChildItem -Path $systemDir -File).FullName
$params = @{
extensionList = $extensionList
}
$jobs = foreach($path in $tmpfileNameList)
{
$params.tmpFilePath = $path
$Job = [powershell]::Create().AddScript($ScriptBlock).AddParameters($params)
$Job.RunspacePool = $RunspacePool
[pscustomobject]@{
Pipe = $Job
Result = $Job.BeginInvoke()
}
}
详见PowerShell.AddParameters Method
。
那么这一行就错了:
while ($Jobs.IsCompleted -contains $false) {
Start-Sleep -Milliseconds 100
}
也应该更改:
while ($Jobs.Result.IsCompleted -contains $false) {
Start-Sleep -Milliseconds 100
}
最后,您可以获得运行空间的结果,如:
$results = $jobs.ForEach({ $_.Pipe.EndInvoke($_.Result) })
PS /> $results
除了上述内容外,还需要改进逻辑,使脚本真正高效。
不应该向每个powershell
实例传递一条路径,而应该将路径的array
($tmpfileNameList
(拆分为块,并为每个实例提供一个要处理的块。
你可以使用这样的东西来分割你的array
:
$groupSize = [math]::Ceiling($tmpfileNameList.Count / $threadNumber)
$counter = [pscustomobject]@{ Value = 0 }
$groups = $tmpfileNameList | Group-Object -Property {
[math]::Floor($counter.Value++ / $groupSize)
}
在这种情况下,由于使用4
线程,$groups
将包含4个组。如果你想把这种技术应用到你的代码中,你可以从这个链接复制逻辑。