Hey, Scripting Guy! I like the idea of using Windows PowerShell jobs in a script. The problem is that I have multiple jobs I want to run. I would like to be able to wait until all the jobs have completed, and then receive the jobs all at once. Is this possible? I looked around at the job cmdlets and I do not see an option to receive all completed jobs. If you cannot do this, it is fine, but I just thought I would ask.
— KB
Hello KB,
Microsoft Scripting Guy Ed Wilson here. It has been a quiet week in Charlotte, North Carolina. No snow has fallen, no rainstorms, just a little fog and some gentle afternoon showers. Of course, the rain showers happened on the day I headed into town to meet with a Microsoft Technical Account Manager (TAM) who had bought some copies of my Windows PowerShell 2.0 Best Practices book for his customers. He was grubbing for autographs, and it gave me a chance to get out of the house. The nice thing about going to the Microsoft Office in Charlotte is I always run into people I know, and it gives me a chance to spread the word about the upcoming 2010 Scripting Games. It was a great day, even if it did rain a little bit.
In between meetings with various TAMs and hanging out in the Hard Drive (our café), I was able to check the scripter@microsoft.com e-mail inbox. KB, I recalled seeing a script written by James, one of the test engineers on the Windows PowerShell team, and I have adapted his script to meet your specific needs (thanks, James).
The ReceiveArrayOfJobs.ps1 script begins by creating an empty array named $arrayJobs. I then add three jobs to the array. The first job is the Get-Service command; the second is the Get-Process command, which pauses execution for a second. Last, a bogus WMI command is added to the array. There is no WMI class named Win32_sofware (this command will generate an error, and is used to illustrate that the script will handle jobs that complete with an error as well as jobs that end correctly). This section of the script is seen here:
$arrayJobs = @()
$arrayJobs += Start-Job { Get-Service }
$arrayJobs += Start-Job { Get-Process ; Start-Sleep -Seconds 1}
$arrayJobs += Start-Job { Get-wmiObject win32_sofware }
In a real-world example, you would probably be running jobs on remote computers. In addition, you probably would not want to hard-code the actual jobs you want to run. You might prefer to read a text file that contains a number of jobs, or use some other sort of device to avoid typing in literal values. This section of the script would be a good one to modify before implementing the script on your network.
After the array of jobs has been created, it is time to monitor the jobs to see if they have completed. To do this, the first thing is to assign the value $false to the variable $complete. The $complete variable will be used to determine when the jobs are all completed. This is shown here:
$complete = $false
If the $complete variable is not equal to $true (or simply stated while it is not complete), the ReceiveArrayOfJobs.ps1 script checks the array of jobs to see if the status of the job is ‘running.’ The while check is shown here:
while (-not $complete) {
If the job is still running, the array of jobs has not completed. To check the state of the array of jobs, the $arrayJobs variable is pipe to the Where-Object cmdlet. Inside the Where-Object cmdlet, the state property of the current object on the pipeline is examined to see if its value matches the string ‘running.’ If a match is found, it is assigned to the $arrayJobsInProgress variable. This continues to happen as long as a match is found for the state property. This section of the script is shown here:
$arrayJobsInProgress = $arrayJobs |
Where-Object { $_.State -match ‘running’ }
If no jobs have the state of running, a value will not be assigned to the $arrayJobsInProgress variable. The “all jobs have completed” string is displayed on the Windows PowerShell console, and the $complete variable is set to $true. This will cause the While loop to complete, because it only runs as long as the $complete variable is equal to $false. This section of the script is seen here:
if (-not $arrayJobsInProgress) { “All Jobs Have Completed” ; $complete = $true }
After the While loop is exited, the Windows PowerShell jobs stored in the $arrayJobs variable are pipelined to the Receive-Job cmdlet and the results from all of the jobs are displayed in the Windows PowerShell console. The complete ReceiveArrayOfJobs.ps1 script is shown here.
ReceiveArrayOfJobs.ps1
$arrayJobs = @()
$arrayJobs += Start-Job { Get-Service }
$arrayJobs += Start-Job { Get-Process ; Start-Sleep -Seconds 1}
$arrayJobs += Start-Job { Get-wmiObject win32_sofware }
$complete = $false
while (-not $complete) {
$arrayJobsInProgress = $arrayJobs |
Where-Object { $_.State -match ‘running’ }
if (-not $arrayJobsInProgress) { “All Jobs Have Completed” ; $complete = $true }
}
$arrayJobs | Receive-Job
When the ReceiveArrayOfJobs.ps1 script is run in the Windows PowerShell ISE, the output is displayed that is shown in the following image.
KB, that is all there is to receiving all Windows PowerShell jobs. This also concludes Windows PowerShell Jobs Week. Tomorrow, we will open the virtual mailbag, and answer those questions that do not require a long explanation. That’s right, it is time once again for the sensation sweeping the scripting nation: Quick-Hits Friday!
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments