Summary: Learn how to use Windows PowerShell to save objects for later offline analysis.
Hey, Scripting Guy! I have a problem. I am trying to examine processes that are consuming resources on my computer. The problem is that when I use the Get-Process cmdlet, my results keep changing before I have a chance to examine thoroughly the output from my last output. I would like a way that I could store the command, and then analyze the results at my leisure. I know I can write to a text file, but I like having an object with which to work. In addition, I know that I can store the results in a variable, but I am a one person IT department at my company. I often have to leave my desk for extended periods of time, which means I cannot leave Windows PowerShell running all the time. What can I do?
—BH
Hello BH,
Microsoft Scripting Guy Ed Wilson here. I record two sessions for TechNet Radio this afternoon. I am beginning a series of monthly podcasts in which I will be discussing Windows PowerShell best practices. Of course, part of the discussion springs from my Microsoft Press book, Windows PowerShell 2.0 Best Practices, but other things discussed derive from things I saw during the 2011 Scripting Games, as well as questions I have received as the Scripting Wife and I have traveled around speaking at various conferences. Indeed, one of the best things about being the Microsoft Scripting Guy is the ability to talk to passionate people who are striving to use Windows PowerShell to solve real-world problems.
One of the things that is really cool about Windows PowerShell is the way it makes working with processes so easy. On my antique laptop, I am very concerned with processes because they eat up precious memory resources, and they drain my aged battery of its limited life. I know I am not the only one in the world who faces restrictions in IT spending; luckily, Windows PowerShell provides a razor sharp tool that allows one to hone in on errant processes.
BH, as you pointed out, it is easy to write process information to a text file. To do this, I use the redirection arrows from inside the Windows PowerShell console. I like to use the alias gps when working with the Get-Process cmdlet from console. The complete command to get all of the process information and write it to a text file is shown here:
gps >>
c:\fso\gps.txt
The output that is stored in the text file is shown here.
Depending on what you are attempting to accomplish, having a nicely formatted text file may just do the trick. On the other hand, if more than limited searching and perusal are in the forecast, a text file quickly outlasts its welcome.
Of course, I can store the results of the command in a variable, and use all the power of Windows PowerShell to parse the data. For example, I can store my process information in a variable, and then sort the processes based on the amount of CPU time the processes are using. In the command that follows, I use the variable $gps to hold the process information that is retrieved by the Get-Process cmdlet. On the second line of the command, I pipe the System.Diagnostics.Process objects to the Sort-Object cmdlet (sort is an alias). I tell the Sort-Object cmdlet that I want to sort on the cpu property and I want that sort to be a descending sort (the biggest numbers on top). These two commands are shown here:
$gps = Get-Process
$gps | sort cpu –Descending
The following figure contains both the commands and the output associated with those commands.
So it is easy to work with process objects in an offline fashion, as long as Windows PowerShell is kept running and the value stored in the $gps variable does not become overwritten. If I need to shut down Windows PowerShell or to reboot my computer, how can I continue to access the same process objects? I use the Export-Clixml cmdlet. I know the name of the cmdlet is a bit confusing, and for some it is downright scary. After all, most network administrators are skittish when it comes to XML.
The cool thing about using the Export-Clixml cmdlet is that you do not need to know anything about XML to use it. All I am doing when I pipe my process information to the Export-Clixml cmdlet is using XML to store a representation of my objects. XML is the perfect choice for this. XML is a rich data store that easily adapts my objects for offline use. The command itself is simplicity and elegance personified. To obtain all the process information, I use the Get-Process cmdlet (gps is an alias), and I pipe the results to the Export-Clixml cmdlet. I provide the Export-Clixml cmdlet with a path to store the resultant XML file. This command is shown here:
gps | Export-Clixml c:\fso\gps.xml
The resultant XML file is an actual XML file and is therefore viewable in an XML viewer, as shown in the following figure.
After I have an XML representation of my process objects, I can import the XML file and work with the objects at any time in the future. I can reboot my computer 100 times, and still be able to open Windows PowerShell and view my offline process objects. In fact, I can use the XML file on a different computer if I need to do so.
To import the XML for use on my computer, I use the Import-CliXML cmdlet. It only needs the path to the XML file. I can store the resultant process objects in a variable for ease of processing. In the following series of commands, I use the Get-Process cmdlet (gps is an alias) to retrieve process information. I pipe the objects to the Export-CliXML cmdlet and provide it with a path to store the resulting XML file. I then use the Import-CliXML cmdlet to import the XML file and store the process objects in the $gps variable. Next, I pipe the process objects to the Where-Object cmdlet (? Is an alias for Where-Object) where I look for process names that match word. The commands that accomplish all this are shown here:
gps | Export-Clixml c:\fso\gps.xml
$gps = Import-Clixml C:\fso\gps.xml
$gps | ? { $_.name -match 'word' }
The commands and associated output are shown in the following figure.
I do not have to store the imported XML in a variable. I can simply use Import-CliXML and pipe the results directly into other Windows PowerShell cmdlets for processing. For example, if I want to look for duplicate processes that are running, I might import the XML file, group (alias for the Group-Object cmdlet) the processes on the name property, and sort (alias for the Sort-Object cmdlet) the results based on the count property in a descending fashion. The command that accomplishes this is shown here:
Import-Clixml C:\fso\gps.xml | group name -NoElement| sort count -des
The command and associated output are shown in the following figure.
One thing to keep in mind when working with Import-CliXML and Export-CliXML is that the created objects are deserialized. This means that the methods normally available to the System.Diagnostics.Process objects are not available. Other than that, they look and behave exactly like normal objects. I can pipe the XML to the Get-Member object to see what is available and what is not available. The command to do this is shown here:
Import-Clixml C:\fso\gps.xml | get-member
The command and associated output are shown here.
Well, that is about all there is to working with offline objects and utilizing the Import-CliXML and Export-CliXML cmdlets. Join me tomorrow for more exciting Windows PowerShell stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy