I’ve been aware of Group-Object for many years, but it’s only the last year or so that I’ve really added it to my daily arsenal of cmdlets and functions. It has become one of my favourite cmdlets and every time I use it, it feels like I’m doing some kind of magic.

So what does Group-Object actually do? Well let’s have a look at the synopsis from Get-Help.

Groups objects that contain the same value for specified properties

That’s all very well, but cut to the chase Anthony, why the hell would I want to do that?

Want to quickly see what OS version your computers in AD are running?

Get-AdComputer -filter * -property OperatingSystem | 
    Group-Object -property OperatingSystem |
    Sort-Object Count -Descending |
    Format-Table -AutoSize
Count Name                                       Group
----- ----                                       -----
  459 Windows 7 Enterprise N                     {CN=COMP54,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP85,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP118,OU=Lab-Computers,DC=domain,D...
  443 Windows 8 Enterprise N                     {CN=COMP17,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP42,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP45,OU=Lab-Computers,DC=domain,DC...
  438 Windows Server 2012 R2 Datacenter          {CN=COMP69,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP80,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP106,OU=Lab-Computers,DC=domain,D...
  437 Windows 10 Pro for Workstations            {CN=COMP36,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP75,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP89,OU=Lab-Computers,DC=domain,DC...
  437 Windows 10 Enterprise 2016 LTSB            {CN=COMP12,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP14,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP32,OU=Lab-Computers,DC=domain,DC...
  436 Windows 10 Enterprise Insider Preview      {CN=COMP44,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP104,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP127,OU=Lab-Computers,DC=domain,...
  433 Windows 8.1 Enterprise N                   {CN=COMP9,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP11,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP26,OU=Lab-Computers,DC=domain,DC=...
  431 Windows Server 2012 R2 Standard            {CN=COMP19,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP95,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP137,OU=Lab-Computers,DC=domain,D...

Now you have a nice table of all the Windows OS versions in your AD along with how many computers with each version exists. Want to be able to easily browse through those groups of objects? You can convert the output to a hashtable using the name of the operating system as they key. Just add the -AsHashTable parameter to Group-Object.

$os = Get-AdComputer -filter * -property OperatingSystem | 
    Group-Object -property OperatingSystem -AsHashTable

Now you have a hash table of all the groups with the keys set to the names of the operating systems and the values of the actual computer objects in those groups.

os-hashtable

Ok, so what if you wanted to check the os version aswell? You can create groups using more than one property. Lets take the above example and add in the OperatingSystemVersion AD attribute too.

Get-AdComputer -filter * -property OperatingSystem, OperatingSystemVersion | 
    Group-Object -property OperatingSystem, OperatingSystemVersion |
    Sort-Object Count -Descending |
    Format-Table -AutoSize
Count Name                                                   Group
----- ----                                                   -----
  459 Windows 7 Enterprise N, 6.1 (7601)                     {CN=COMP54,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP85,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP118,OU=Lab-Computers...
  443 Windows 8 Enterprise N, 6.2 (9200)                     {CN=COMP17,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP42,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP45,OU=Lab-Computers,...
  438 Windows Server 2012 R2 Datacenter, 6.3 (9600)          {CN=COMP69,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP80,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP106,OU=Lab-Computers...
  437 Windows 10 Pro for Workstations, 10.0 (16299)          {CN=COMP36,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP75,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP89,OU=Lab-Computers,...
  437 Windows 10 Enterprise 2016 LTSB, 10.0 (14393)          {CN=COMP12,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP14,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP32,OU=Lab-Computers,...
  436 Windows 10 Enterprise Insider Preview, 10.0 (16188)    {CN=COMP44,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP104,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP127,OU=Lab-Computer...
  433 Windows 8.1 Enterprise N, 6.3 (9600)                   {CN=COMP9,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP11,OU=Lab-Computers,DC=domain,DC=lab, CN=COMP26,OU=Lab-Computers,D...

Nifty.

Group-Object is also great for finding duplicates. Carlos Perez has a fantastic blog post where he uses Group-Object to removed duplicate usernames from a fake user data set. Once he had created the fake user set using fakenamegenerator, he used Group-Object to group all entries on username and then selected only one object from each group.

Import-Csv -Path $Path | Group-Object Username | Foreach-Object {
                $_.group | Select-Object -Last 1} | Export-Csv -Path $OutPath

Fun fact. I ran Group-Object to remove duplicates from a fake user set of 20000 records. In PowerShell 5.1 it took almost a minute. In PowerShell 6.1 it took less than 1 second!

The real strength of Group-Object, is the possibility to provide a script block to run arbitrary code to generate the group names. Have a look at this tweet sized solution to a problem Scott Hanselman posted on twitter.

So what’s happening here? First we use Get-ChildItemto get the directory contents, then after piping to Group-Object, the script block takes each object coming down the pipeline and runs the substring method against the name to extract the first 7 characters of the folder name, which equates to “yyyy-MM” on which the folders get grouped in to. After the next pipe we then run a foreach-object and use the group’s name as the name of the destination folder to copy the contents of the group to.

magic

Group-Object is a tool that has many uses. From making sense of data sets, to finding the frequency of objects, to even removing duplicates. Hopefully you’ll also start using Group-Object if it isn’t already in your toolkit of go to cmdlets.

Happy grouping!