Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I have started setting up groups like:

  • Department-staff
    • Department-supervisors
      • Department-director

Where Department-supervisors is a member of Department-staff, and Department-director is a member of Department-supervisors.

I know how to use powershell to list what groups a person is a member of, either directly assigned, or inherited though the nested groups.

But what I'm trying to figure out is a script that will show me all the users who are members of one of those groups BOTH directly and indirectly, eg. User A is a direct member of Department-staff and Department-director.

My googling fails me in trying to find or write a script that can do that.

Edit:

In reality, there are more layers and branches to the nesting, and many departments, so it gets confusing. I want to get a list of members who are part of any group directly, and also a member of the same group indirectly so I can remove the redundant group direct memberships.

share|improve this question
    
If your users are only direct members of a single group (they shouldn't need multiple direct right?), then your list would be anyone who is not a direct member of Department-staff. Only members of Department-supervisors and Department-director would be members of both a direct group and an indirect, or two, group(s). –  jscott May 22 '13 at 18:10
    
@jscott that sounds insightful...but I'm not quite following you...perhaps I need more coffee. –  Grant May 22 '13 at 18:48
add comment

2 Answers

up vote 2 down vote accepted

The following will walk a given parent group (name must be compatible with Get-ADGroupMember syntax) and populate two hashes. One hash will have user sAMAccountName as the key and a array of direct group memberships as the value. The second hash will contain keys of all processed groups.

It will correctly detect, and skip, circular group nestings (e.g. parent is child of child). You can comment out the Write-Host lines for less line noise in the console.

Import-Module ActiveDirectory

function Walk-Group ( $group ) {

    Get-ADGroupMember $group | Group-Object objectClass -ash | Foreach-Object {

        # Add each user to $users hash, add current group to their collection
        if ( $_.user ) {
            foreach ( $u in $_.user.GetEnumerator() ) {
                if ( $users[$u.sAMAccountName] ) {
                    $users[$u.sAMAccountName] += $group
                } else {
                    $users.Add( $u.sAMAccountName, @($group) )
                }
            }
        }

        # Recurse into each child group, skip if group is circular member
        if ( $_.group ) {
            foreach ( $g in $_.group.GetEnumerator() ) {
                if ( $groups[$g.Name] ) {
                    Write-Host "Existing:" $g.Name
                } else {
                    Write-Host "New Group:" $g.Name
                    $groups.Add( $g.Name, $true )
                    Walk-Group $g.Name
                }
            }
        }

    }
}

# Hash to collect user/group info.
$users = @{}

# Hash to collect processed groups.
$groups = @{}

# Root group to walk
Walk-Group "Department-staff"

# Display users with mulitple direct memberships
$users.GetEnumerator() | Where-Object { $_.Value.Count -gt 1 }
share|improve this answer
    
Beautiful, that's exactly what I was looking for. Thanks so much! –  Grant May 28 '13 at 12:53
add comment

EDIT: based on your updated description something like this should work. Note that I didn't take care of loops in group membership so you might find it running forever.

$RootGroup=Get-ADGroup "your group here" 
$username = "test user here"

Function RecurseMembership( $FromAbove, $username ) 
{
"------------------------------------------------------"
    $FromAbove


    $LevelUsers=$FromAbove | Get-ADGroupMember | where { $_.objectClass -eq "user" -and $_.SamAccountName -eq "$username" }
    $LevelGroups=$FromAbove | Get-ADGroupMember | where { $_.objectClass -eq "group" }

    $LevelUsers
    $LevelGroups | ForEach-Object { RecurseMembership $_ $username } 

}

RecurseMembership $RootGroup $username 
share|improve this answer
    
Excellent site, and a very useful script, but doesn't do what I need. –  Grant May 22 '13 at 18:49
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.