概述
想要调用一个带有参数的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_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-Job”创建后台作业。
有人可以帮我解决这个问题吗?
答案 0 :(得分:6)
您可以查看模块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
(默认为处理器计数)以提高性能。
答案 1 :(得分:4)
这不是一个新问题,但我觉得它缺少一个包括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.
答案 2 :(得分: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
}
作业完成后,它将立即显示所有输出。没有混淆。
答案 3 :(得分: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'
答案 4 :(得分:0)
您可以在收到所有工作后通过执行以下操作获得结果:
$阵列= @() Get-Job -Name * |其中{$阵列+ = $ _。ChildJobs.output}
.ChildJobs.output将包含每个作业中返回的任何内容。