Powershell 使用运行空间而不是foreach循环的多线程

Powershell 使用运行空间而不是foreach循环的多线程,powershell,foreach,parallel-processing,Powershell,Foreach,Parallel Processing,我有一个带有foreach循环的脚本。它有十几个功能,每个功能都从远程机器的C$共享中收集信息(剪切文本文件、检查文件版本等) 然而,这需要一些时间,因为每台机器的数据都是在一个接一个地收集之后收集的。(有时它以500+输入运行) 我们希望将其放入并行执行的运行空间中,但到目前为止,还没有任何示例起作用。我对这个概念很陌生 当前脚本的大纲 $inputfile=c:\temp\computerlist.txt 职能1 职能2 职能3等 foreach循环 职能1 职能2 职能3 现在,所有结果都

我有一个带有foreach循环的脚本。它有十几个功能,每个功能都从远程机器的C$共享中收集信息(剪切文本文件、检查文件版本等)

然而,这需要一些时间,因为每台机器的数据都是在一个接一个地收集之后收集的。(有时它以500+输入运行)

我们希望将其放入并行执行的运行空间中,但到目前为止,还没有任何示例起作用。我对这个概念很陌生

当前脚本的大纲 $inputfile=c:\temp\computerlist.txt

职能1 职能2 职能3等

foreach循环 职能1 职能2 职能3


现在,所有结果都将通过write host写入屏幕。

此示例并行ping多个服务器,因此您可以根据需要轻松修改它:

Add-Type -AssemblyName System.Collections

$GH = [hashtable]::Synchronized(@{})

[System.Collections.Generic.List[PSObject]]$GH.results = @()
[System.Collections.Generic.List[string]]$GH.servers = @('server1','server2','server3');
[System.Collections.Generic.List[string]]$GH.functions = @('Check-Server');

[System.Collections.Generic.List[PSObject]]$jobs = @()


#-----------------------------------------------------------------
function Check-Server {
#-----------------------------------------------------------------

   # a function which runs parallel

   param(
        [string]$server
    )

    $result = Test-Connection $server -Count 1 -Quiet 
    $GH.results.Add( [PSObject]@{ 'Server' = $server; 'Result' = $result } )

}

#-----------------------------------------------------------------
function Create-InitialSessionState {
#-----------------------------------------------------------------

    param(
        [System.Collections.Generic.List[string]]$functionNameList
    )

    # Setting up an initial session state object
    $initialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()

    foreach( $functionName in $functionNameList ) {

        # Getting the function definition for the functions to add
        $functionDefinition = Get-Content function:\$functionName
        $functionEntry = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $functionName, $functionDefinition

        # And add it to the iss object
        [void]$initialSessionState.Commands.Add($functionEntry)
    }

    return $initialSessionState
}

#-----------------------------------------------------------------
function Create-RunspacePool {
#-----------------------------------------------------------------

    param(
        [InitialSessionState]$initialSessionState
    )

    $runspacePool = [RunspaceFactory]::CreateRunspacePool(1, ([int]$env:NUMBER_OF_PROCESSORS + 1), $initialSessionState, $Host)
    $runspacePool.ApartmentState = 'MTA'
    $runspacePool.ThreadOptions  = "ReuseThread"
    [void]$runspacePool.Open()

    return $runspacePool
}


#-----------------------------------------------------------------
function Release-Runspaces {
#-----------------------------------------------------------------

    $runspaces = Get-Runspace | Where { $_.Id -gt 1 }

    foreach( $runspace in $runspaces ) {
        try{
            [void]$runspace.Close()
            [void]$runspace.Dispose()
            }
        catch {
        }
    }
}


$initialSessionState = Create-InitialSessionState -functionNameList $GH.functions
$runspacePool        = Create-RunspacePool -initialSessionState $initialSessionState


foreach ($server in $GH.servers)
{
    Write-Host $server

    $job = [System.Management.Automation.PowerShell]::Create($initialSessionState)
    $job.RunspacePool = $runspacePool

    $scriptBlock = { param ( [hashtable]$GH, [string]$server ); Check-Server -server $server }

    [void]$job.AddScript( $scriptBlock ).AddArgument( $GH ).AddArgument( $server )
    $jobs += New-Object PSObject -Property @{
                                    RunNum = $jobCounter++
                                    JobObj = $job
                                    Result = $job.BeginInvoke() }

    do {
        Sleep -Seconds 1 
    } while( $runspacePool.GetAvailableRunspaces() -lt 1 )

}

Do {
    Sleep -Seconds 1
} While( $jobs.Result.IsCompleted -contains $false)


$GH.results

Release-Runspaces | Out-Null

[void]$runspacePool.Close()
[void]$runspacePool.Dispose()

这将是并发的,总共大约需要10秒。如果计算机正常工作,它可能会在本地主机上运行三次

invoke-command comp1,comp2,comp3 { sleep 10; 'done' } 
简单尝试api(线程):


你的剧本是什么?我相信远程计算机上的invoke命令已经在后台运行了。是的,但是invoke命令不能在这种环境中使用。我正在编写简单的函数来检查文件版本,或者剪切.log文件字符串,等等。。。这都是通过C$的份额,但现在每个周期都是一个接一个。。。对于500多台机器,它可能需要数小时。有很多方法可以在后台运行、作业、启动流程、工作流。。。嗨,你知道为什么当ping不成功时脚本会停止吗?我试图修改ping部分,当ping成功时,它只会将结果添加到$GH.results。无论哪种方式,它在第一台无法ping的机器上挂起而没有任何错误消息。
$a =  [PowerShell]::Create().AddScript{sleep 5;'a done'}
$b =  [PowerShell]::Create().AddScript{sleep 5;'b done'}
$c =  [PowerShell]::Create().AddScript{sleep 5;'c done'}
$r1 = $a.BeginInvoke(); $r2 = $b.BeginInvoke() $r3 = $c.BeginInvoke()
$a.EndInvoke($r1); $b.EndInvoke($r2); $c.EndInvoke($r3)

a done
b done
c done