Discover relationships by using Group-Object in PowerShell
Summary: Learn how to use one of the most basic Windows PowerShell cmdlets, the Group-Object cmdlet, to see relationships among different objects.
There are some things in life that just seem to always go together: jasmine flowers and green tea, scones and English breakfast tea, or even peanut butter and apples. In the world of Windows PowerShell, there are things that go together as well. It seems that I always do the same kinds of things:
- Get data
- Group data
- Sort data
- Output data
For the next few days, I want to focus on the second and third items, grouping data and sorting data.
Group-Object: A basic cmdlet
No matter what I am doing with Windows PowerShell, it seems that I always need to group stuff together. I get a list of processes, and now what? Well, I want to correlate the processes together. And, how do I do that? I do it by grouping things together. Maybe it’s a process name or a resource utilization. It might even be when the process was created. All of these things make sense at one time or another.
For example, suppose I want to find all processes on my system that have more than one instance running. To do this, I need to group the processes by name. I can use the Get-Process cmdlet (gps is an alias) to get all of the processes. But, after I have the processes, what do I do? Obviously, I need to find how many processes with the same name are in existence. But to do this without the Group-Object cmdlet would be to step back in time. I can remember using ADO to do this sort of grouping in the old days. I actually wrote a subroutine that did this. Dude! In Windows PowerShell, we get this capability for free. I just pipeline Get-Process to Group-Object. Because I am interested in grouping process names (as opposed to memory or processor utilization), I specify the name of the property, which is name.
The command is shown here:
Get-Process | Group-Object name
The command and output are shown in the figure here:
Group where what’s up?
The above output from the previous command is less than illuminating. I mean, it’s not in order, and there are lots and lots of processes where there is only one instance running. So, I want to filter out processes that occur only once. To do this, I need the grouping that takes place in the Group-Object cmdlet because that is where all the names are correlated with one another. So, I know how many processes of each name I actually have. The following would not work!
Get-Process | ? name -gt 1 | Group-Object name
The command does not generate an error. It just returns erroneous information. Actually, the information is correct as far as the command goes, but it just does not meet the expectations. The output is shown here:
If I say, “Oh, yeah, I need to filter the count property,” and so I change the command to the following, it still won’t work. Only, this time it returns nothing.
PS C:\> Get-Process | ? count -gt 1 | Group-Object name
So, I have to get the processes, and then I have to group the processes so that I can filter my output. Here are the steps:
- Get processes using Get-Process
- Group the output using Group-Object
- Filter the output using Where-Object
The command is shown here:
Get-Process | Group-Object name | Where-Object count -gt 1
I can shorten this command by using aliases as shown here:
gps | group name | ? count -gt 1
The commands and output are shown here:
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. Also check out my Microsoft Operations Management Suite Blog. See you tomorrow. Until then, peace.
Ed Wilson Microsoft Scripting Guy