Home > OS >  Formatting Compare-Object output in a non-tech-user-friendly way
Formatting Compare-Object output in a non-tech-user-friendly way

Time:07-30

Background: I have two Active Directory groups that control access to a specific service. Membership in either group grants access. Each user that has access uses one license, which is billed to the end customer. Belonging to both groups still only requires one license per user. To better track and account for these licenses, I need to regularly report group membership for these two groups and compare them to get a license count for billing.

Where I started: Using powershell commands, I can easily compare the two groups and list the output.

Compare-Object (Get-ADGroupMember 'group1') (Get-ADGroupMember 'group2') -Property 'Name' -IncludeEqual

Compare-Object gives you a list like this:

Name                    SideIndicator
----                    -------------
Mary Jones              =>
David Davies            ==
George Jetson           <=
Frank Herbert           <=
Leif Erikson            ==
Chris Columbus          =>
Francis Drake           ==

But I'm looking to format it something like this:

Name                    Group1     Group2
----                    ------     ------
Mary Jones                           X
David Davies              X          X
George Jetson             X
Frank Herbert             X
Leif Erikson              X          X
Chris Columbus                       X
Francis Drake             X          X

It doesn't need to be exactly like that, but I need something a little more readable than ==, =>, and <=.

Suggestions?

CodePudding user response:

The table that Compare-Object shows in the console isn't its real output, it is just how PowerShell's formatting system automatically displays objects, that consist of up to three properties.

By applying some pipelined | operations, these objects can be transformed as necessary to produce the desired output.

Compare-Object (Get-ADGroupMember 'group1') (Get-ADGroupMember 'group2') -Property 'Name' -IncludeEqual |
     ForEach-Object {
         [PSCustomObject] @{
             Name   = $_.Name
             Group1 = if( $_.SideIndicator -in '<=', '==' ) {'x'} else {''}
             Group2 = if( $_.SideIndicator -in '=>', '==' ) {'x'} else {''}

             # Improved syntax for PS 7.x:
             # Group1 = $_.SideIndicator -in '<=', '==' ? 'x' : ''
             # Group2 = $_.SideIndicator -in '=>', '==' ? 'x' : ''
         }
     } |
     Format-Table Name,
                  @{ expression = 'Group1'; align = 'center' },
                  @{ expression = 'Group2'; align = 'center' }

Output:

Name           Group1 Group2
----           ------ ------
David Davies     x      x
Leif Erikson     x      x
Francis Drake    x      x
Mary Jones              x
Chris Columbus          x
George Jetson    x
Frank Herbert    x

(The order is different due to my sample data, but that shouldn't matter.)

Explanations:

  • By piping to ForEach-Object we can process each object (row) that is output by Compare-Object one-by-one. Within ForEach-Object's script block, the automatic variable $_ stands for the current object.
  • Using [PSCustomObject] @{ ... }, we create an anonymous object, that is implicitly output by PowerShell.
  • The Name property is just copied, obviously.
  • Depending on the value of the SideIndicator property, we create the values for the Group1 and Group2 properties - either an 'x' or an empty string ''. It may come as a surprise that you can assign the output of an if statement to a property like this. It works like the ternary operator in other programming languages. Since PowerShell 7.x you no longer need this somewhat clumsy construct and can use a real ternary operator, as shown in the commented lines of the code sample.
  • Finally, we pipe to Format-Table to control the alignment of the Group1 and Group2 columns. You can leave out the Format-Table call if the default left-alignment is sufficient. The syntax @{ ... } in this context defines a calculated property. For more information see the Format-Table docs for the -Property parameter and the About Calculated Properties page.

Bonus code:

Just for fun, here is another variant to calculate the Group1 and Group2 properties. Finding out how it works is left as an exercise for the reader.

Group1 = $_.SideIndicator -replace '<=|==', 'x' -replace '=>'
Group2 = $_.SideIndicator -replace '=>|==', 'x' -replace '<='
  • Related