web-dev-qa-db-ja.com

Powershell:複数のジョブを並行して実行し、バックグラウンドジョブのストリーミング結果を表示します

概要

引数を取り、各ジョブをバックグラウンドで実行し、詳細な出力を表示する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"を使用する求人。

誰かがこれを理解するのを手伝ってくれませんか?

15
talbert.houle

モジュール 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(デフォルトはプロセッサ数)を増やします。

6
Roman Kuzmin

新しい質問ではありませんが、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.
5
Piazzolla

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
}

ジョブが完了するとすぐに、すべての出力が表示されます。混同されることなく。

1
E.V.I.L.

複数のジョブを実行したい場合は、出力をマッサージして、どのジョブがどのジョブに対応しているかをコンソールで直接確認することをお勧めします。

$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'   
1
mjolinor

すべてのジョブが受信された後、次のようなことを行うことで結果を得ることができます。

$ array = @()Get-Job -Name * |場所{$ array + = $ _。ChildJobs.output}

.ChildJobs.outputには、各ジョブで返されたすべてのものが含まれます。

0
powerkor