12

ÜbersichtPowershell: Führen Sie mehrere Aufträge in parralel und Blick Streaming Ergebnisse von Hintergrundjobs

Suchen Sie ein Powershell-Skript aufrufen, die in einem Argument nimmt, läuft jeden Job im Hintergrund, und zeigt mir die ausführliche Ausgabe.

Problem bei mir läuft in

Das Skript wird ausgeführt, aber ich möchte dies durch Streaming die Ergebnisse der Hintergrundjobs, um sicher zu überprüfen, wie sie ausgeführt werden.

-Code

###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 

Was ich zur Zeit zu sehen:

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

Was ich sehen will:

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 

ich in der Lage sein wollen, die Ausgabe oder Speicher zu sehen, die irgendwo so kann ich wieder sicher sein das Skript beziehen lief und sehen, welche Server neu gestartet usw.

Fazit:

In der Vergangenheit I lief das Skript und es ging durch die Aktualisierung der Server einzeln und gab mir die Ausgabe, die ich wollte, aber als ich anfing, mehr Server zu tun - diese Aufgabe dauerte zu lange, weshalb ich versuche, Hintergrund-Jobs mit "Start - Job".

Kann mir bitte jemand helfen, das herauszufinden?

Antwort

4

Sie können sich das Modul SplitPipeline ansehen. Es ist speziell für solche Aufgaben konzipiert. Der Arbeits Demo-Code ist:

# 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 

Für Ihre Aufgabe ersetzen "processing server $_"; sleep 1 (simuliert eine langsame Arbeit) mit einem Aufruf an das Skript und verwenden Sie die Variable $_ als Eingabe der aktuellen Server.

Wenn jeder Job nicht prozessorintensiv ist, erhöhen Sie den Parameter Count (der Standardwert ist Prozessoranzahl), um die Leistung zu verbessern.

+0

Roman, danke für deine Antwort. Dies ist das nächste, was ich erreichen konnte, um die Ausgabe genau so zu bekommen, wie ich es wollte. Ich bekomme einige zusätzliche Ausgabefehler, die ich beheben werde, aber diese Methode führt nicht nur mein Skript aus, sondern zeigt mir die Ausgabe, die ich möchte. Vielen Dank. –

+0

@ talbert.houle, Ich bin froh, dass Sie dieses Werkzeug nützlich finden. Wenn Sie Ideen haben, wie Sie es verbessern können, können Sie sie gerne auf der Projektseite einreichen. –

1

In Ihrer ForEach-Schleife sollten Sie die Ausgabe erfassen, die von den bereits ausgeführten Jobs generiert wird.

Beispiel Nicht

Geprüft
$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 
} 

Nun, wenn Sie diese alle Ihre Ergebnisse tun gemischt werden. Vielleicht möchten Sie Ihre ausführliche Ausgabe mit einem Stempel versehen, um festzustellen, von welcher Ausgabe sie stammt.

Oder

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 
} 

Es zeigt alle Ausgaben, sobald ein Auftrag abgeschlossen ist. Ohne durcheinander zu sein.

+0

Vielen Dank für Ihre Informationen. Leider habe ich den ersten Codeblock ausprobiert, und alles, was ich auf dem Bildschirm erhalten habe, war "Job auf Server starten". Habe über 20 Minuten gewartet, um sicherzustellen, dass das Skript auf dem Remote-Server ausgeführt wurde, und das ist alles, was ich erhalte. Werde den zweiten Codeblock versuchen und sehen, ob sich etwas ändert. –

+0

[Hier ist ein Link] (http://www.powershellmagazine.com/2013/02/13/pstip-streaming-results-from-background-jobs-in-powershell-3-0/) zu etwas, das mehr sein könnte hilfreich. –

1

Wenn mehrere Jobs gleichzeitig bearbeitet werden sollen, möchten Sie wahrscheinlich die Ausgabe massieren, um zu gewährleisten, dass die Ausgabe für den jeweiligen Job direkt auf der Konsole verfügbar ist.

$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

Wenn ich durch diesen Code gehe, läuft das Skript direkt über der "While" -Anweisung, und ich bekomme keine Ausgabe an die Konsole. –

+0

Das einzige, was ich weiß, wäre, dass $ Server leer/null ist. Ich habe mit diesem scritpblock für die Jobaktion getestet: {foreach ($ i in 1..10) {get-date; sleep -Second 2}} um einen Job zu erstellen, der 20 Sekunden lang ausgeführt wird und alle 2 Sekunden eine Ausgabe erzeugt $ servers = (1..3) als Serverliste. – mjolinor

3

Keine neue Frage, aber ich fühle es eine Antwort fehlt einschließlich Powershell-Workflows und seine parallele Möglichkeiten verwenden, von Powershell-Version 3. Welche weniger Code ist und vielleicht verständlicher als das Starten und für Arbeitsplätze warten, die von Natürlich funktioniert das auch gut.

Ich habe zwei Dateien: TheScript.ps1, die die Server koordiniert und BackgroundJob.ps1, die eine Art von Überprüfung durchführt. Sie müssen sich im selben Verzeichnis befinden.

Die Write-Output im Hintergrund Job-Datei schreibt in den gleichen Strom, den Sie beim Start TheScript.ps1 sehen.

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 (zum Beispiel):

param (
    [Parameter(Mandatory=$true)] [string] $server 
) 

Write-Host "[$server]`t Processing server $server" 
Start-Sleep -Seconds 5 

Also, wenn die TheScript.ps1 Start wird es "Verarbeitungsserver" 3 mal schreiben, aber es wird nicht warten, 15 Sekunden, sondern 5, weil sie parallel laufen.

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

Ich mag, dass diese Antwort keine 3rd-Party-Bibliothek benötigt! –

0

Sie die Ergebnisse, indem Sie so etwas wie dies, nachdem alle Aufträge empfangen wurden erhalten können:

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

.ChildJobs.output hat alles, was in jedem Job zurückgegeben wurde.

Verwandte Themen