Learn about Windows PowerShell
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 do—provide an illustrative technique for working with Windows PowerShell jobs—but 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
Hello 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.
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_softwarePS C:\> $rtnId 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 $rtnInvalid class + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], ManagementException + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommandPS C:\> Receive-Job get*PS C:\> Receive-Job $rtnPS 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.Commandgwmi win32_softwarePS 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-JobPS C:\> Get-JobPS 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:\> $rtnId Name State HasMoreData Location Command-- ---- ----- ----------- -------- -------5 Job5 Running True localhost gwmi win32_productPS C:\> Wait-Job -Id 5Id Name State HasMoreData Location Command-- ---- ----- ----------- -------- -------5 Job5 Completed True localhost gwmi win32_productPS C:\>PS C:\> $prod = Receive-Job -Id 5PS C:\> $prod.Count145PS 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-JobPS C:\> Get-Job $rtnGet-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-JobId Name State HasMoreData Location Command-- ---- ----- ----------- -------- -------1 Job1 Stopped True localhost gwmi win32_productPS C:\> $products = Receive-Job -Id 1PS C:\> $products.count73
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 nameName----XML Notepad 2007PowerShellPackCatalyst Control Center InstallProxyMicrosoft Office Visio Professional 2007Microsoft Office OneNote MUI (English) 2007Microsoft Office Groove Setup Metadata MUI (English) 2007Microsoft Office InfoPath MUI (English) 2007Microsoft Office Visio MUI (English) 2007Microsoft Office Access MUI (English) 2007Microsoft Office Shared Setup Metadata MUI (English) 2007Microsoft Office Excel MUI (English) 2007Microsoft Office Shared 64-bit Setup Metadata MUI (English) 2007Microsoft Office Access Setup Metadata MUI (English) 2007Microsoft Office PowerPoint MUI (English) 2007Microsoft Office Publisher MUI (English) 2007Microsoft Office Outlook MUI (English) 2007Microsoft Office Office 64-bit Components 2007Microsoft Office Shared 64-bit MUI (English) 2007Microsoft 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
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.