3

I'm trying to make a PS script which would list all Active Directory user group membership (recursive).

I already have working script:

import-module activedirectory

$users = get-aduser -Filter {Name -Like "*"} -Searchbase "ou=Users, dc=Domain" | Where-Object { $_.Enabled -eq 'True' } 

$targetFile = "D:\users.csv"
rm $targetFile
Add-Content $targetFile "User;Group"


foreach ($user in $users)
{
    $groups = Get-ADPrincipalGroupMembership $user

    foreach ($group in $groups)
    {
        $username = $user.samaccountname
        $groupname = $group.name
        $line = "$username;$groupname"
        Add-Content $targetFile $line
    }
}

But script doesn't list groups recursively, i.e., if group listed in the output file is part of another group.

Example:

Group1: User

Group2: Group3: User

Script shows only Group1 and 3 but not 2.

What should I add to the first script that it writes group membership recursively?

ekad
  • 14,436
  • 26
  • 44
  • 46
Phoneutria
  • 351
  • 4
  • 9
  • 17
  • You should recursively query `Get-ADPrincipalGroupMembership` for a group, for those group you haven't queried yet. – Vesper May 27 '14 at 12:41

5 Answers5

6

Sorry I am publishing an answer for a question from 3 years ago but if someone will see it, it can help.
Credit to:
How to get ALL AD user groups (recursively) with Powershell or other tools?

You can use the LDAP_MATCHING_RULE_IN_CHAIN:

Get-ADGroup -LDAPFilter "(member:1.2.840.113556.1.4.1941:=CN=User,CN=USers,DC=x)"

You can use it anywahere that you can use an LDAP filter.

Example:

$username = 'myUsername'
$dn = (Get-ADUser $username).DistinguishedName
Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn) | select -expand Name | sort Name  

Fix in your script:

import-module activedirectory

$users = get-aduser -Filter {Name -Like "*"} -Searchbase "ou=Users, dc=Domain" | Where-Object { $_.Enabled -eq 'True' } 

$targetFile = "D:\users.csv"
rm $targetFile
Add-Content $targetFile "User;Group"

foreach ($user in $users)
{
$dn = $user.DistinguishedName
    $groups = Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn) | select -expand Name | sort Name

    foreach ($group in $groups)
    {
        $username = $user.samaccountname
        $groupname = $group.name
        $line = "$username;$groupname"
        Add-Content $targetFile $line
    }
}
E235
  • 11,560
  • 24
  • 91
  • 141
2

If you make it a function you can call it recursively. Check this out, I think you'll be pleased with the results:

Function Get-ADGroupsRecursive{
Param([String[]]$Groups)
    Begin{
        $Results = @()
    }
    Process{
        ForEach($Group in $Groups){
            $Results+=$Group
            ForEach($Object in (Get-ADGroupMember $Group|?{$_.objectClass -eq "Group"})){
                $Results += Get-ADGroupsRecursive $Object
            }
        }
    }
    End{
        $Results | Select -Unique
    }
}

Toss that at the top of your script, and then call it for each user. Something like:

import-module activedirectory

$users = get-aduser -Filter {Name -Like "*"} -Searchbase "ou=Users, dc=Domain" -Properties MemberOf | Where-Object { $_.Enabled -eq 'True' } 

$targetFile = "D:\users.csv"
rm $targetFile
Add-Content $targetFile "User;Group"


foreach ($user in $users)
{
    $Groups = $User.MemberOf
    $Groups += $Groups | %{Get-ADGroupsRecursive $_}
$Groups | %{New-Object PSObject -Property @{User=$User;Group=$_}}|Export-CSV $targetfile -notype -append
}

Now, depending on the size of your AD structure that may take quite a while, but it will get you what you were looking for.

TheMadTechnician
  • 34,906
  • 3
  • 42
  • 56
  • Thanks for the code you provided. But I get error "The term 'Get-ADGroupsRecursive' is not recognized as the name of a cmdlet, function, script file, or operable program." – Phoneutria May 28 '14 at 06:29
  • Then you did not put the function that I provided at the top of your script and you tried to run the second part of what I provided either before it or without it entirely. – TheMadTechnician May 28 '14 at 07:09
  • You're right, now that part works. But I get error on append part. – Phoneutria May 28 '14 at 07:25
  • Perhaps you should update your question with what you are using and post the error that you are getting at this point. – TheMadTechnician May 28 '14 at 15:32
  • Invalid null key at `$Groups | %{New-Object PSObject -Property @{User=$User;$Group=$_}}|Export-CS ..` – makerofthings7 May 15 '15 at 00:17
  • @LamonteCristo Thank you! I'm sure that's why the user got errors. I have corrected the script, and it should work now. Removed a $ from `@{User=$User;$Group=$_}` so that it now reads `@{User=$User;Group=$_}` – TheMadTechnician May 15 '15 at 00:53
2

Newer versions of PowerShell (AD Module) do have -Recursive switch. So you can easily use Get-ADGroupMember.

Example: Get-ADGroupMember -Identity My_Group -Recursive

1

It is very easy. Just use ActiveRoles Management Shell for Active Directory. Cmdlet Get-QADMemberOf with parameter Indirect is the one you are looking for. Example:

Get-QADMemberOf john.smith -Indirect

1

The Quest object returned already include All Recursive groupes (and first level users) in properties $_.AllMembers

Add-PSSnapin Quest.ActiveRoles.ADManagement
$UsersFirstLevel = ($Members | Get-QADObject -Type Group -DontUseDefaultIncludedProperties | Get-QADGroupMember -DontUseDefaultIncludedProperties | ?{$_.type -eq 'user'})
$UsersSubGroup = ($Members | Get-QADObject -Type Group -DontUseDefaultIncludedProperties | Get-QADGroupMember -DontUseDefaultIncludedProperties | ?{$_.type -eq 'group'}).Allmembers | Get-QADObject -DontUseDefaultIncludedProperties | ?{$_.type -eq 'user'}

$RecursiveUsers = $UsersFirstLevel
$RecursiveUsers += $UsersSubGroup
$RecursiveUsers = $RecursiveUsers | Sort-Object -Unique
Alban
  • 3,105
  • 5
  • 31
  • 46