Summary: Microsoft Scripting Guy, Ed Wilson, teaches how to use the Windows PowerShell Group-Object cmdlet to organize data.
Hey, Scripting Guy! I have been using Windows PowerShell more these days. I find it really easy to use, and I like the way I can find things. But what I need is a better way to view things. For example, I have been saving stuff as a CSV file, and then opening the data in Microsoft Excel. This works OK, but I would like to be able to avoid the middleman so to speak. In other words, I want to be able to group information so it is easier to read. Can you think of a shortcut for grouping information?
—MS
Hello MS,
Microsoft Scripting Guy, Ed Wilson, is here. MS, I am glad that you are using Windows PowerShell more on a daily basis. In fact, learning Windows PowerShell makes a great New Year’s resolution, which is something it seems that some people are actually doing, based on tweets coming across on Twitter. In a couple of weeks, Tim Bolton writes a guest blog that talks about why it is good to learn Windows PowerShell, and in his initial email to me, he stated that this was something he wrestled with for quite some time.
One of the things about learning to use Windows PowerShell is that Windows PowerShell can slice-and-dice data so easily. It becomes a quick data analysis tool that allows network administrators, analysts, and others to parse data to quickly discover and remediate issues. It can also be used to audit baseline information, or even to spelunk through reams of statistical data.
One cmdlet that allows this analysis is the Group-Object cmdlet. In its most basic form, the Group-Object cmdlet accepts a property from objects in a pipeline, and it gathers up groups that match that property and displays the results. For example, to check on the status of services on a system, pipe the results from the Get-Service cmdlet to the Group-Object cmdlet and use the Status property. The command is shown here.
Get-Service | Group-Object -Property status
The command to group services based on the status of the service, along with its resultant output is shown in the following image.
In the Group field of the output from the Group-Object cmdlet, the objects that are grouped appear. The output indicates that each grouped object is an instance of a ServiceController object. This output is a bit distracting.
In situations, where the grouping is simple, the Group output might actually be useful. An example of this is the grouping of numbers, as shown in the image that follows. (Group is an alias for Group-Object).
If the grouping information does not add any value, omit it by using the NoElement switched parameter. The revised command to display the status of services and the associated output are shown in the image that follows.
One of the cool things to do with the Group-Object cmdlet is to use it to return a hash table of information. I have written extensively about hash tables in the past on the Hey, Scripting Guy! Blog; and in fact, I even wrote an entire week of blogs that talked about the basics of using hash tables.
Here are the steps for using the Group-Object cmdlet to return a hash table of information:
- Pipe the objects to the Group-Object cmdlet.
- Use the AsHashTable switched parameter and the AsString switched parameter.
- Store the resulting hash table in a variable.
An example of using these steps is shown in the code that follows.
$hash = Get-Service | group status -AsHashTable –AsString
After it is created, view the hash table by displaying the content that is stored in the variable. This technique is shown here.
PS C:\> $hash
Name Value
---- -----
Running {System.ServiceProcess.ServiceController, System.S...
Stopped {System.ServiceProcess.ServiceController, System.S...
At this point, the output does not appear to be more interesting than a simple grouping. But, the real power appears when accessing the key properties (those stored under the Name column). To access the objects stored in each of the key values, use dotted notation, as shown here.
$hash.running
The command to create the hash table of service information and to access the running services by using dotted notation are shown in the image that follows.
I can index into the collection by using square brackets and selecting a specific index number. This technique is shown here.
PS C:\> $hash.running[5]
Status Name DisplayName
------ ---- -----------
Running AudioEndpointBu... Windows Audio Endpoint Builder
If I am interested in a particular running service, I can pipe the results to the Where-Object cmdlet (the question mark is an alias for Where-Object). This technique is shown here.
PS C:\> $hash.running | ? {$_.name -match "bfe"}
Status Name DisplayName
------ ---- -----------
Running BFE Base Filtering Engine
In addition to being able to group directly by a property, such as running services, it is also possible to group based on a script block. The script block becomes sort of a where clause. To find the number of services that are running, and support a stop command, use the Group-Object cmdlet and a script block. This command is shown here.
PS C:\> Get-Service | group {$_.status -eq "running" -AND $_.canstop}
Count Name Group
----- ---- -----
61 True {System.ServiceProcess.ServiceController, System....
115 False {System.ServiceProcess.ServiceController, System....
MS, that is all there is to using the Group-Object cmdlet to group data. I invite you to join me tomorrow for more Windows PowerShell goodness.
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