Bookmark and Share

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! Your examples this week on using Windows PowerShell jobs have all been from the command line. Is it possible to use Windows PowerShell jobs in a script? If so, how would I do it?

-- AG

 

Hey, Scripting Guy! AnswerHello AG,

Microsoft Scripting Guy Ed Wilson at your service. The fog covers my front lawn like a down blanket draped casually across a feather tick. My eyes reflect the early morning display of slumber, and my mind seems to echo the noisy silence brought about by last night’s temperature inversion. I was up late last night (or this early morning, depending on your perspective) on a conference call with my mentee Jit who lives in Canberra, Australia. Late at night in Charlotte is morning in Australia. We were talking about a huge Exchange migration project he is planning, and discussing various ways to use Windows PowerShell scripting to ease the transition as well as to facilitate the movement and consolidation of users.

I always enjoy talking with Jit because he is extremely smart. For obvious reasons, I prefer to talking to him in person as I did last year when I was down under teaching an advanced Windows PowerShell workshop (Australia is an awesome place. It’s one of the Scripting Wife’s favorite countries.) During one weekend there, Jit, Chris, Pete, the Scripting Wife, and I headed down to the shore to take pictures and to do some scuba diving. I took the following picture on our way to our second shore dive of the day. As you can see, it was kind of fun walking in my dry suit carrying more than 100 pounds of equipment.

Photograph Ed took on an Australian beach

 

AG, to use jobs in a script, you will use the same procedures we used on Monday and on Tuesday.

In the UseJobsToGetProcessAndService.ps1 script, two jobs are used. The first job uses the Get-Process cmdlet to return a list of processes, and the second job uses the Get-Service cmdlet to return a list of services. This is shown here:

Start-Job -Name process -ScriptBlock { Get-Process }
Start-Job -Name Service -ScriptBlock { Get-Service }

On my computer, the script runs so fast that the jobs do not have time to complete, so I slowed it down by a few seconds to allow time for the jobs to complete. To do this, I used the Start-Sleep cmdlet and told it to wait for three seconds. This is shown here:

"Pausing for 3 seconds ..."
start-sleep -Seconds 3

After I am done pausing the script, I use the Foreach statement to loop through the jobs that have been registered on the computer. I use the $job variable to hold each job object that is returned from the Get-Job cmdlet. This is shown here:

Foreach ($job in Get-Job)
 

I do not want to attempt to receive the job if it is still running. Therefore, I check the state of the job by inspecting the state property on the job object. If the state of the job is reported as completed, I then use the Receive-Job cmdlet to return the completed job. Because I am only working with one job at a time, I can use the job.id property from the job object to receive the job. I also use the command property and the id property to display a status message before actually receiving the job. This is shown here:


  if($job.state -eq 'Completed')
    {
     "Receiving job id $($job.id) which executes $($job.command)`r`n"
     Start-Sleep -Seconds 1
     Receive-Job -Id $job.id
    }

If the job has not completed, I display a status message that states the job is still running. This is shown here:

  else
    {
     "$($job.id ) job is still running $($job.command)"
    }

The last thing I do is clear the job queue by using the Get-Job cmdlet to retrieve all job objects and pipelining it to the Remove-Job cmdlet. The force parameter is required to remove any jobs that may be still executing. In real life, you may not want to do this, but for the sake of a demonstration script, it makes sense. Besides, it could be a useful technique when you inadvertently create long-running jobs because of a programming error:

Get-Job | Remove-Job –force

The complete UseJobsToGetProcessAndService.ps1 script is shown here.

UseJobsToGetProcessAndService.ps1

Start-Job -Name process -ScriptBlock { Get-Process }
Start-Job -Name Service -ScriptBlock { Get-Service }
"Pausing for 3 seconds ..."
start-sleep -Seconds 3

Foreach ($job in Get-Job)
 {
  if($job.state -eq 'Completed')
    {
     "Receiving job id $($job.id) which executes $($job.command)`r`n"
     Start-Sleep -Seconds 1
     Receive-Job -Id $job.id
    }
  else
    {
     "$($job.id ) job is still running $($job.command)"
    }
 }
 Get-Job | Remove-Job -force

When the script runs inside the Windows PowerShell ISE, the output appears that is shown in the following image. The various Start-Sleep commands make it possible for you to easily see that each job is being retrieved. You have to carefully watch the output window, but you should be able to see each job.id and job.command displayed for a second before the information scrolls on the screen.

Image of script output in Windows PowerShell ISE



AG, that is all there is to using jobs in a script. Windows PowerShell Jobs Week will continue tomorrow.

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