12

概述PowerShell的:从后台作业

展望调用PowerShell脚本,它接受一个参数,在后台运行的每个作业,让我看到详细的输出运行在parralel和视点视频流效果多个作业。

问题我遇到

脚本似乎运行,但我想他们正在运行流媒体后台作业的结果来验证这一点是肯定的。

代码

###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_it\psscripts\PSPatch.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 

我希望能够看到输出或存储在某个地方,所以我可以返回,以确保脚本运行,看看哪些服务器重启等

结论:

在过去,我运行脚本,并逐步更新服务器,并给我输出我想要的,但是当我开始做更多的服务器时 - 这项任务花费了很长时间,这就是为什么我试图使用“Start-工作”。

任何人都可以帮我解决这个问题吗?

回答

4

您可以查看模块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(默认值是处理器数量)以提高性能。

+0

罗马,谢谢你的回答。这是最接近我可以得到完全按照我想要的输出。我收到一些额外的输出错误,我将排除故障,但这种方法不仅运行我的脚本,而且显示我希望的输出。谢谢。 – 2013-03-26 12:50:31

+0

@ talbert.houle,我很高兴你觉得这个工具很有用。如果您有关于如何使其更好的想法,欢迎您在项目现场提交。 – 2013-03-26 13:54:33

1

在您的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 
} 

将尽快在作业完成全部显示输出。没有被混淆。

+0

谢谢您的信息。不幸的是,我尝试了第一个代码块,并且我在屏幕上收到的所有内容都是“在服务器名称上启动作业”。已经等了20分钟以确保脚本在远程服务器上运行,这就是我所收到的。将尝试第二个代码块,看看是否有任何改变。 – 2013-03-25 14:32:26

+0

[这里是一个链接](http://www.powershellmagazine.com/2013/02/13/pstip-streaming-results-from-background-jobs-in-powershell-3-0/)可能更多很有帮助。 – 2013-03-25 14:51:45

1

如果你想在正在进行的多个作业,你可能会想按摩输出,以帮助保持什么样的输出与哪个工作直接在控制台上。

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


ForEach($server in $servers) 
{ 
    Start-Job -FilePath c:\cefcu_it\psscripts\PSPatch.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' 
+0

当我逐句通过此代码时,脚本正在运行“While”语句,并且没有收到任何输出到控制台。 – 2013-03-25 14:29:17

+0

我知道唯一会导致$ server为空/ null的东西。我使用这个scritpblock进行了测试:{foreach($ i in 1..10){get-date; sleep -Seconds 2}}创建一个运行20秒的作业,并且每2秒产生一次输出,并且$ servers =(1..3)作为服务器列表。 – mjolinor 2013-03-25 16:04:53

3

不是一个新问题,但我觉得它缺少一个答案使用工作流和它并行的可能性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. 
+0

我喜欢这个答案不需要第三方库! – 2016-11-16 09:24:51

0

你可以得到所有的作业均已收到之后做这样的事情的结果:

$阵列= @() GET-工作-Name * |其中{$阵列+ = $ _。ChildJobs.output}

.ChildJobs.output将有在每个作业返回任何东西。