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-Objectwe can process each object (row) that is output byCompare-Objectone-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
Nameproperty is just copied, obviously. - Depending on the value of the
SideIndicatorproperty, we create the values for theGroup1andGroup2properties - either an'x'or an empty string''. It may come as a surprise that you can assign the output of anifstatement 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-Tableto control the alignment of theGroup1andGroup2columns. You can leave out theFormat-Tablecall if the default left-alignment is sufficient. The syntax@{ ... }in this context defines a calculated property. For more information see theFormat-Tabledocs for the-Propertyparameter 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 '<='
