Hey, Scripting Guy! How Can I Manage Windows PowerShell Jobs?

Hey, Scripting Guy! How Can I Manage Windows PowerShell Jobs?

  • Comments 1
  • Likes

Bookmark and Share 

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I am not sure how much help running the Get-Process cmdlet as a job is going to be for me in my work environment. I kind of get what you are trying to doprovide an illustrative technique for working with Windows PowerShell jobsbut I have things that take a really long time. I need to know not only how to run that process as a job, but also how to kill that process if it is eating too many resources. Is there a way to manage Windows PowerShell jobs after they have been created?

-- BP

 

Hey, Scripting Guy! AnswerHello BP,

Microsoft Scripting Guy Ed Wilson here. I am listening to Miles Davis on my Zune HD, while mulling over the e-mail sent to scripter@microsoft.com. I made a pot of Krauter Tea using some tea I brought back from Germany. Krauter tea goes really well with choco Leibniz biscuits, a German made biscuit. I was in Berlin teaching a WMI class, and really enjoyed walking around Potsdamer Platz and drinking tea in some of the outdoor cafes. There is a really cool train system there that allows you to roam all over the city. The following photograph is one I took on one of these walks during a particularly clear night. The interplay of ambient light and softly curved mass make this picture one of my favorite photographs from that trip, with the possible exception of some from the Brandenburg Gate that I will show you in a later article. Berlin is a great town for taking pictures.

Photograph Ed took in Berlin, Germany

 

BP, before we look at managing Windows PowerShell jobs, I want to spend a bit more time talking about running Windows PowerShell jobs, expounding on our discussion from yesterday.

When starting a Windows PowerShell job via the Start-Job cmdlet, you can assign a name to hold the returned job object. You can also assign the returned job object in a variable by using a straight forward value assignment. If you do both, you end up with two copies of the returned job object. This is shown here.

PS C:\> $rtn = Start-Job -Name getSoftware -ScriptBlock {gwmi win32_software}
PS C:\> Get-Job -Name get*

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
1               getSoftware     Completed  True            localhost            gwmi win32_software


PS C:\> $rtn

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
1               getSoftware     Completed  True            localhost            gwmi win32_software

Retrieving the job, via the Receive-Job cmdlet, consumes the data. You cannot come back and retrieve the returned data again. This code shown here illustrates this concept.

PS C:\> Receive-Job $rtn
Invalid class
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], ManagementException
    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

PS C:\> Receive-Job get*
PS C:\> Receive-Job $rtn
PS C:\>

This example also shows what happens when a scriptblock returns an error. When you use the Receive-Job the error message displays. To find additional information about the code that triggered the error, use the Job object stored in either the $rtn variable, or the GetSoftware named job. I prefer using the job object stored in the $rtn variable as seen here.

PS C:\> $rtn.Command
gwmi win32_software
PS C:\>

There is no Win32_software WMI class. The correct WMI class is Win32_product. First, remove the leftover job objects by getting the jobs and removing the jobs. This is shown here:

PS C:\> Get-Job | Remove-Job
PS C:\> Get-Job
PS C:\>

When you create a new Windows PowerShell job, it runs in the background. There is no indication if the job ended in an error or if it was successful. Indeed, you do not have any idea when the job even completes, other than to use the Get-Job cmdlet several times to see when the job state changes from Running to Completed. For many jobs this may be perfectly acceptable. In fact, it may even be preferable because you wish to regain control of the Windows PowerShell console as soon as the job begins executing. On other occasions, you may want to be notified when the Windows PowerShell job completes. To do this, you can use the Wait-Job cmdlet. Give the Wait-Job cmdlet either a job name or a job ID. After you have done this, the Windows PowerShell console will pause until the job completes. The job is displayed on the console with its completed status. You can then use the retrieve job cmdlet to receive the deserialized objects and store them in a variable. As shown here, you can then use the count property to see how many software packages are installed on the computer:

PS C:\> $rtn = Start-Job -ScriptBlock {gwmi win32_product}
PS C:\> $rtn

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
5               Job5            Running    True            localhost            gwmi win32_product


PS C:\> Wait-Job -Id 5

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
5               Job5            Completed  True            localhost            gwmi win32_product


PS C:\>
PS C:\> $prod = Receive-Job -Id 5
PS C:\> $prod.Count
145
PS C:\>

In a newly open Windows PowerShell console, the Start-Job cmdlet is used to start a new job. The returned job object is stored in the $rtn variable. You can pipe the job object contained in the $rtn variable to the Stop-Job cmdlet to stop the execution of the job. If you try to use the job object in the $rtn variable directly to get job information, an error will be generated. This is shown here:

PS C:\> $rtn = Start-Job -ScriptBlock {gwmi win32_product}
PS C:\> $rtn | Stop-Job
PS C:\> Get-Job $rtn
Get-Job : The command cannot find the job because the System.Management.Automation.PSRemotingJob name was not found. Verify the value of the Name parameter, and then try the command again.
At line:1 char:8
+ Get-Job <<<<  $rtn
    + CategoryInfo          : ObjectNotFound: (System.Manageme...n.PSRemotingJob:String) [Get-Job], PSArgumentException
    + FullyQualifiedErrorId : JobWithSpecifiedNameNotFound,Microsoft.PowerShell.Commands.GetJobCommand

You can pipe the job object to the Get-Job cmdlet and see that the job is in a stopped state. Use the Receive-Job cmdlet to receive the job information, and the count property to see how many software products are included in the variable, as shown here:

PS C:\> $rtn | Get-Job

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
1               Job1            Stopped    True            localhost            gwmi win32_product


PS C:\> $products = Receive-Job -Id 1
PS C:\> $products.count
73

In the above list you can see that only 73 software packages were enumerated. This is because the Get-Wmiobject command to retrieve information from the Win32_Product class did not have time to finish. In fact, it was stopped about half way in progress. If you wish to see the name of all the installed software packages, pipe the received job items (stored in the $products variable) to the Select-Object cmdlet and choose the name. The output is shown here, in truncated fashion:

PS C:\> $products | Select name

Name
----
XML Notepad 2007
PowerShellPack
Catalyst Control Center InstallProxy
Microsoft Office Visio Professional 2007
Microsoft Office OneNote MUI (English) 2007
Microsoft Office Groove Setup Metadata MUI (English) 2007
Microsoft Office InfoPath MUI (English) 2007
Microsoft Office Visio MUI (English) 2007
Microsoft Office Access MUI (English) 2007
Microsoft Office Shared Setup Metadata MUI (English) 2007
Microsoft Office Excel MUI (English) 2007
Microsoft Office Shared 64-bit Setup Metadata MUI (English) 2007
Microsoft Office Access Setup Metadata MUI (English) 2007
Microsoft Office PowerPoint MUI (English) 2007
Microsoft Office Publisher MUI (English) 2007
Microsoft Office Outlook MUI (English) 2007
Microsoft Office Office 64-bit Components 2007
Microsoft Office Shared 64-bit MUI (English) 2007
Microsoft Office Groove MUI (English) 2007
…Truncated output …

To see all the job related cmdlets, use the Get-Command cmdlet with the –noun parameter and look for things related to jobs. Use the Select-Object cmdlet to retrieve only the cmdlet names. This is shown here:

PS C:\> Get-Command -Noun *job* | Select-Object name

 

Name

----

Get-Job

Receive-Job

Remove-Job

Start-Job

Stop-Job

Wait-Job

 

 

PS C:\>

BP, at this point, we have now looked at all six of the job-related Windows PowerShell cmdlets. 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

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Ed and Craig,

    When you have started some long time job which does some very important stuff for next 7 hours....or that was your plan.

    But after 5 hours you noticed that "damn..7 hours is far not enough". How do you step-in into the job and see in which position that is. And then stop it at next controlled sequence.