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 byCompare-Object
one-by-one. WithinForEach-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 theGroup1
andGroup2
properties - either an'x'
or an empty string''
. It may come as a surprise that you can assign the output of anif
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 theGroup1
andGroup2
columns. You can leave out theFormat-Table
call if the default left-alignment is sufficient. The syntax@{ ... }
in this context defines a calculated property. For more information see theFormat-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 '<='