Powershell show users who are members of a group twice - once directly once indirectly

Solution 1:

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 }

Solution 2:

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