Prof. Powershell

More Group Play with Group-Object

Nifty trick that shows you by name what processes you'd typically have to guess at when calling up the ParentProcessID property.

Last time, I showed you ways to use the groupinfo object you get with the Group-Object cmdlet. Here's a refresher using Get-WmiObject:

Get-WmiObject -Class win32_process | Sort-Object -Property ParentProcessID | Group-Object -Property ParentProcessID | Sort -Property Count -descending

This expression gets all processes on the computer sorted by the ParentProcessID and then groups them together. Here's an output sample:

Count Name   Group
----- ----   -----
   37 744    {\\SERENITY\root\cimv2:Win32_Process.Handle="2...
   20 3396   {\\SERENITY\root\cimv2:Win32_Process.Handle="3...
    6 3184   {\\SERENITY\root\cimv2:Win32_Process.Handle="3...
    3 676    {\\SERENITY\root\cimv2:Win32_Process.Handle="7...

But the ParentProcessID gives me meaningless info. I'd rather like to know the name of that process. The Group-Object cmdlet not only takes a property name to group by, but it allows you to create a custom property based on a script block. The following is technically a one-line PowerShell expression, but I've broken it up into lines to make it easier to follow:

Get-WmiObject -Class win32_process -outvariable data |
Sort-Object -Property ParentProcessID | Group-Object -Property {
$ptid=$_.parentProcessID
$p=$data | where {$_.processID -match $ptid}
$p.name} |
Sort -Property Count -descending

This is a little more involved, so let me quickly walk through it. I'm still getting the process objects from WMI but this time I'm saving the output to a variable called data. I'll need this later. The sorting is the same.

When I get to Group-Object, I'm defining a new property in the script block. This code in the { } is executed and whatever is written to the pipeline is used as the grouping value. Very simply, I save the value of the ParentProcessID from the piped in object to a variable, $ptid.

Next, I search my stored results for the process whose processID matches the parentprocess ID. For the sake of clarity this is saved as $p. The actual value I'm grouping on is the name property of $p.

The results are then sorted and displayed:

Count Name         Group
----- ----         -----
   37 services.exe {\\SERENITY\root\cimv2:Win32_Process.Handle="2...
   20 explorer.exe {\\SERENITY\root\cimv2:Win32_Process.Handle="3...
   17              {\\SERENITY\root\cimv2:Win32_Process.Handle="4...
    5 svchost.exe  {\\SERENITY\root\cimv2:Win32_Process.Handle="4...

One of the groups doesn't have a name, which most likely indicates a parent process that is no longer running, or there is no parent process ID. Assuming I saved the last expression to a variable, I can easily identify them:

PS C:\> $r | where {-not $_.name} | select -ExpandProperty Group | Select Name

Name
----
System
System Idle Process
smss.exe
wininit.exe
csrss.exe

I'll be back next time with one more group lesson.

About the Author

Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.

comments powered by Disqus
Most   Popular