概要
引数を取り、各ジョブをバックグラウンドで実行し、詳細な出力を表示する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
出力を表示したり、どこかに保存したりして、スクリプトが実行されたことを確認し、どのサーバーが再起動したかを確認できるようにしたいのですが、.
結論:
以前は、スクリプトを実行してサーバーを1つずつ更新し、必要な出力を提供していましたが、サーバーを増やし始めると、このタスクに時間がかかりすぎたため、バックグラウンドを使用しようとしています"Start-Job"を使用する求人。
誰かがこれを理解するのを手伝ってくれませんか?
モジュール 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バージョン3から、ワークフローを使用したPowershellとその並列の可能性を含む回答が欠けていると感じています。
2つのファイルがあります: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
「Processing server」を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_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'
すべてのジョブが受信された後、次のようなことを行うことで結果を得ることができます。
$ array = @()Get-Job -Name * |場所{$ array + = $ _。ChildJobs.output}
.ChildJobs.outputには、各ジョブで返されたすべてのものが含まれます。