Powershell:在parralel中运行多个作业,并查看后台作业的流式结果



概述

希望调用一个Powershell脚本,该脚本接受一个参数,在后台运行每个作业,并向我显示详细的输出。

我遇到的问题

脚本似乎正在运行,但我想通过在后台作业运行时流式传输其结果来验证这一点。

代码

###StartServerUpdates.ps1 Script###
#get list of servers to update from text file and store in array
$servers=get-content c:serverstoupdate.txt
#run all jobs, using multi-threading, in background
ForEach($server in $servers){
  Start-Job -FilePath c:cefcu_itpsscriptsPSPatch.ps1 -ArgumentList $server
}
#Wait for all jobs
Get-Job | Wait-Job
#Get all job results
Get-Job | Receive-Job

我目前看到的情况:

Id              Name            State      HasMoreData     Location             Command                  
--              ----            -----      -----------     --------             -------                  
23              Job23           Running    True            localhost            #patch server ...        
25              Job25           Running    True            localhost            #patch server ...        

我想看的内容:

Searching for approved updates ...
Update Found:  Security Update for Windows Server 2003 (KB2807986)
Update Found:  Windows Malicious Software Removal Tool - March 2013 (KB890830)
Download complete.  Installing updates ...
The system must be rebooted to complete installation.
cscript exited on "myServer" with error code 3.
Reboot required...
Waiting for server to reboot (35)
Searching for approved updates ...
There are no updates to install.
cscript exited on "myServer" with error code 2.
Servername "myServer" is fully patched after 2 loops

我希望能够看到输出或将其存储在某个地方,这样我就可以回头查看脚本是否运行,并查看哪些服务器重新启动,等等。

结论:

在过去,我运行脚本,它一次更新一个服务器,并给我我想要的输出,但当我开始做更多的服务器时,这项任务花费了太长时间,这就是为什么我试图在"启动作业"中使用后台作业。

有人能帮我弄清楚吗?

您可以查看SplitPipeline模块。它是专门为这类任务设计的。工作演示代码是:

# import the module (not necessary in PS V3)
Import-Module SplitPipeline
# some servers (from 1 to 10 for the test)
$servers = 1..10
# process servers by parallel pipelines and output results immediately
$servers | Split-Pipeline {process{"processing server $_"; sleep 1}} -Load 1, 1

对于您的任务,将"processing server $_"; sleep 1(模拟慢速作业(替换为对脚本的调用,并使用变量$_作为输入,即当前服务器。

如果每个作业不是处理器密集型作业,则增加参数Count(默认为处理器计数(以提高性能。

这不是一个新问题,但我觉得它缺少了一个答案,包括Powershell使用工作流及其并行可能性,从Powershell版本3开始。这是更少的代码,也许比开始和等待工作更容易理解,当然这也很好。

我有两个文件:协调服务器的TheScript.ps1和进行某种检查的BackgroundJob.ps1。它们需要在同一目录中。

后台作业文件中的Write-Output写入启动TheScript.ps1时看到的相同流。

TheScript.ps1:

workflow parallelCheckServer {
    param ($Servers)
    foreach -parallel($Server in $Servers)
    {
        Invoke-Expression -Command ".BackgroundJob.ps1 -Server $Server"
    }
}
parallelCheckServer -Servers @("host1.com", "host2.com", "host3.com")
Write-Output "Done with all servers."

BackgroundJob.ps1(例如(:

param (
    [Parameter(Mandatory=$true)] [string] $server
)
Write-Host "[$server]`t Processing server $server"
Start-Sleep -Seconds 5

因此,当启动TheScript.ps1时,它将写入"处理服务器"3次,但不会等待15秒,而是等待5秒,因为它们是并行运行的。

[host3.com]  Processing server host3.com
[host2.com]  Processing server host2.com
[host1.com]  Processing server host1.com
Done with all servers.

ForEach循环中,您需要获取已经运行的作业生成的输出。

未测试示例

$sb = {
     "Starting Job on $($args[0])"
     #Do something
     "$($args[0]) => Do something completed successfully"
     "$($args[0]) => Now for something completely different"
     "Ending Job on $($args[0])"
}
Foreach($computer in $computers){
    Start-Job -ScriptBlock $sb -Args $computer | Out-Null
    Get-Job | Receive-Job
}

现在,如果你这样做,你的所有结果都会好坏参半。您可能需要在详细的输出上打上一个印记,以判断哪个输出来自。

Foreach($computer in $computers){
    Start-Job -ScriptBlock $sb -Args $computer | Out-Null
    Get-Job | ? {$_.State -eq 'Complete' -and $_.HasMoreData} | % {Receive-Job $_}
}
while((Get-Job -State Running).count){
    Get-Job | ? {$_.State -eq 'Complete' -and $_.HasMoreData} | % {Receive-Job $_}
    start-sleep -seconds 1
}

一旦作业完成,它将显示所有输出。不会混淆。

如果您想要进行多个作业,您可能需要对输出进行调整,以帮助在控制台上保持与哪个作业对应的输出。

$BGList = 'Black','Green','DarkBlue','DarkCyan','Red','DarkGreen'
$JobHash = @{};$ColorHash = @{};$i=0

ForEach($server in $servers)
{
  Start-Job -FilePath c:cefcu_itpsscriptsPSPatch.ps1 -ArgumentList $server |
   foreach {
            $ColorHash[$_.ID] = $BGList[$i++]
            $JobHash[$_.ID] = $Server
           }
}
  While ((Get-Job).State -match 'Running')
   {
     foreach ($Job in  Get-Job | where {$_.HasMoreData})
       {
         [System.Console]::BackgroundColor = $ColorHash[$Job.ID]
         Write-Host $JobHash[$Job.ID] -ForegroundColor Black -BackgroundColor White
         Receive-Job $Job
       }
    Start-Sleep -Seconds 5
   } 
 [System.Console]::BackgroundColor = 'Black'   

在收到所有作业后,您可以通过这样做来获得结果:

$array=@((获取作业-名称*|其中{$array+=$_.ChildJobs.output}

ChildJobs.output将包含在每个作业中返回的任何内容。

相关内容

  • 没有找到相关文章

最新更新