PowerShell Problem Solver: Active Directory Group Members

Today’s PowerShell problem focuses on a very common IT task, which is grabbing members of an Active Directory group. Now, I’m already going to assume that you have the latest version of Remote Server Administration Tools (RSAT) installed and configured to use the Active Directory PowerShell module. Today’s problem is one I came across recently, where the goal of the task was to list members of an Active Directory group and show a few select user properties.

When you run Get-ADGroupMember, it looks like you get some user objects.

Listing AD Group Members with PowerShell (Image Credit: Jeff HIcks)
Listing AD Group Members with PowerShell (Image Credit: Jeff HIcks)

The original solution to get user details looks something like this:

Get-ADGroupMember -Identity "Chicago IT" |
Select samAccountName,Name,
@{Name="DisplayName";Expression={(Get-ADUser $_.distinguishedName -Properties Displayname).Displayname}},
@{Name="Title";Expression={(Get-ADUser $_.distinguishedName -Properties Title).title}}

On one hand I actually applaud this effort because it demonstrates using Select-Object to define properties from a completely separate source. And it works.

A complicate Select-Object solution
A complicate Select-Object solution (Image Credit: Jeff HIcks)

But it is probably not the best solution. Let’s take a step back.
The first thing I would do in this situation is to see what type of object is coming from the Get-ADGroupMember cmdlet by piping the command to Get-Member.

Using Get-Member
Using Get-Member (Image Credit: Jeff Hicks)

One thing I might look for would be a property or method that I could use to get the information I’m after. In this particular case the ADPrincipal class appears to be a subset of the user object. So, I need the user object.
We already know we can use Get-ADUser. But is there a smarter way? Don’t guess. Read the help.

Reading cmdlet help
Reading cmdlet help (Image Credit: Jeff HIcks)

The Identity parameter needs some sort of identifier, such as the distinguished name or samAccountname. Even though the help file says the cmdlet accepts pipeline input by value, it also says above that you can set this parameter to an object instance. But let’s test.

Testing pipeline input
Testing pipeline input (Image Credit: Jeff Hicks)

How about that. Now let’s try with an object. My test group only has a few members so let’s save them to a variable.

$a = Get-ADGroupMember -Identity "Chicago IT"

We’ll try piping one of the objects to Get-ADUser. Remember this ADPrincipal object has several properties that we can use to get the user account, so I’m optimistic.

Testing a pipeline object
Testing a pipelined object (Image Credit: Jeff Hicks)

Excellent. I can now revise my original command to something a bit more streamlined and efficient.

Get-ADGroupMember -Identity "Chicago IT" | Get-ADUser -Properties Displayname,Title |
Select DistinguishedName,samAccountName,Name,Displayname,Title
A better pipelined solution
A better pipelined solution (Image Credit: Jeff Hicks)

As a bonus, I think this expression is also easier to understand. Now I have something that will work for any group. Although if you are only interested in user accounts, I might suggest one small addition:

Get-ADGroupMember -Identity "Chicago All Users" -Recursive |
Where objectclass -eq 'user' |
Get-ADUser -Properties Displayname,Title,Department |
Select DistinguishedName,samAccountName,Name,Displayname,Title,Department |
Export-CSV c:\work\ChicagoAll.csv

Active Directory groups can contain other groups, as well as computer accounts, so I’m adding a step to filter with Where-Object so that I only keep user objects. You could use similar techniques if you are reporting on group or computer objects.

But the main take away is the process of looking at objects with Get-Member from the first part of your expression and then trying to discover how you can hook that into the input for the next expression, and yes, you might have to read a little help and experiment. But once you get a handle on this it will become second nature, and you’ll be using PowerShell to accomplish all sorts of tasks you didn’t know you could do.