Listing AD Group Members Recursively with Powershell

The Quest Active Directory Cmdlets are very useful in getting AD group members. The only thing I was missing, was a -Recursive parameter. So I created this script.

You feed it AD Group Names as a parameter, and it will return a nice tree view of all members and subgroups and their members and so on. Finally, it returns a list of allunique members and their email addresses. You can easily modify the script to include other properties and export the ouput to a csv file.

I hope you like it.

Hugo

Get-MyGroupMembersRecursive (Rename to .ps1)

62 thoughts on “Listing AD Group Members Recursively with Powershell”

  1. Thanks Hugo. I support Exchange. Quite often, people want to audit the members of a group to see who is getting the email. for large groups with many nestings, this is a pain. Previously, I could try and looking at the message tracking logs from previous emails. that stinks. I could add the list to the Outlook To: line and expand each dlist. Very time consuming.

    I’ve used this script a few times now and I’m so grateful. Thanks!

    You wouldn’t have any thoughts on how to copy a group with its members. Of course the root group has many nested groups. I was planning on simply using the new-qadgroup tool with some of the logic you used here.

    1. Hello JoJoMonkeyMan,
      Thanks so much for taking the time to comment on my website. I appreciate it.
      I’ll think about your question. I’ll have to test some things before I can answer you.
      Hugo

  2. Tnx for this script. I am new to Powershell, so could you please tell me how to view te members of one AD group. Where can I put the name of my group into your script? Tnx for the answer

  3. I Changed the extension of the script to ListGroupMembers.ps1
    How do I execute? Within Powershell he won’t do it. I already installed
    AD extension…..

    Tnx for you quick answer

  4. Really neat script. I like it. However, being new to scripting/Powershell, I am not sure how to handle the following: when I run this script against a distribution list that is 90-95% exteranl contacts, it does not display any of the external contacts. How can I see those external email addresses. I need this for a request to export these addresses to another user. Also, how can I reroute the output to a text file? Command line arguement/redirect such as >group.txt?

    thanks…

    1. Thanks. As for your questions: I don’t know the answer to the first one off the top of my head. Exporting to a text file is easy: you can use the >group.txt just like in DOS, but you can also add the followinf to the last line of the script:
      | Out-File D:\groups.txt

  5. Great script. Saved me lot of time doing the same, as I had already wasted a day trying to figure this, and was not getting the results sorted properly, When I stumbled on this script, it definitely made my day. Great job, and kudos! Cheers RS.

  6. Is it some how possible to use this script to export all groups with members like Get-MyGroupMembersRecursive *

    By the way I’am already very happy with this one.

  7. For the command output, how do i get the full output to a text file. Redirecting the console output to a text file only gives me the last section of members and not the tree view. Simular deal if I add the | out-file option on the last line.

  8. Hi.

    I would also like to thank for this most excellent script. Also if anyone have found a neat and tidy way to pipe the output of the first part to a file, let me know?

    1. Hi Tommy,
      Thanks for the compliment.
      Try this: remove the last 4 lines from the script and replace all occurances of Write-Host text with Out-File text -FilePath ‘d:\scripts\output.txt’ -Append
      Hugo

  9. I just love a script that works. Within 2 minutes of finding this post, your script gave me the data that I was looking for. Unfortunately since you did such a great job, I’m now going to have to spend some time looking at what else you’ve got up here. ;)

    Great work.

  10. Sorry if the question has been asked, but how do you pass the group name as an argument. I’m completely new to Powershell and this script will perform a need I have. If an example could be provided I will be extremely helpful.

  11. I have yet to find an answer to my dilema. I need to seach all users in a specific OU to see what groups they belong to. If theyare missing membership to a specific group I need to have it added. Here is what I have so far but I think i am a bit off the mark.
    $users = Get-QADUser -SearchRoot ‘OU=Enabled,OU=Users,OU=Partners,DC=xxx,DC=com’-MemberOf ‘Allpartners’
    $un = read-Host “User Name domain\username” # Your domain and username
    $pw = read-host “Enter password” -AsSecureString # Your Password
    connect-QADService -service ‘xxx.com’ -ConnectionAccount $un -ConnectionPassword $pw

    ForEach ($user in $Users) {Where-Object -FilterScript ($_.Memberof -ne ‘Allpartners’)} {
    add-QADGroupMember -identity “CN=AllPartners,OU=Groups,OU=Partners,DC=xxx,DC=com” -member $user
    Set-QADUser -Identity $user -ObjectAttributes @{primaryGroupID=@(222753)}
    Remove-QADGroupMember -Identity ‘Domain Users’ -Member $user
    }

  12. Hugo – you are a PS Rockstar – you just made my day, and if you are ever in the Phoenix area, let me know and I’ll get you all liquored up!

  13. Couple of caveats:
    What if my group has spaces in its name “xxxx xx xxx” and is in another domain?

    I typically use “-service” and point to a DC in that domain.
    Thoughts?
    Brian

    1. I think spaces should be no problem, but give it a try.
      Connecting to a different domain was not incorporated in the script, but should be simple to add to all the Get-QAD* cmdlets.
      Hugo

  14. Got this error when running the script. Ideas??

    Cannot validate argument on parameter ‘Identity’. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    At :line:26 char:25
    + $Object = Get-QADObject <<<< $DN

  15. Thanks for this script. Simple and effective. Made one edit for my purposes which displays the Group Name as it goes through the subgroups:

    added $Object.Name in the Write-Host line right before the Indent

  16. $ldap = “YOUR_LDAP_PATH_HERE”

    $de = new-object directoryservices.directoryentry(“LDAP://” + $ldap)
    $ds = new-object directoryservices.directorysearcher($de)

    #$ds.filter = ‘(&(samaccountname=*))’
    $rc = $ds.findall()

    foreach($person in $rc)
    {
    $entry = $person.getdirectoryentry()

    write-host “#################################################”
    write-host “@ ” $entry.name
    write-host “#################################################”
    write-host Group Membership `n——————

    foreach($groupName in $entry.memberof )
    {
    $g = $groupname.tostring(); $g.substring(3,$g.indexof(“,”)-3)
    #$groupname
    }

    write-host
    }

  17. Sorry had the filter set up wrong. It should now only find user objects. This will find all user objects under the given OU.

    ——————–

    $ldap = “LDAP_PATH_HERE”

    echo ” “;
    $de = new-object directoryservices.directoryentry(“LDAP://” + $ldap)
    $ds = new-object directoryservices.directorysearcher($de);

    $ds.filter = “(&(samaccountname=*))”
    $rc = $ds.findall();

    foreach($person in $rc)
    {
    $entry = $person.getdirectoryentry()

    echo “#################################################”
    echo “@ $entry.name”
    echo “#################################################”
    echo “Group Membership `n——————”

    foreach($groupName in $entry.memberof )
    {
    $g = $groupname.tostring(); $g.substring(3,$g.indexof(“,”)-3)
    #$groupname
    }

    echo ” ”
    }

  18. Sorry had the filter set up wrong. It should now only find user objects. This will find all user objects under the given OU.

    ————————————–

    $ldap = “LDAP_PATH_HERE”

    $account = read-host “Which user? ( * for all)”

    echo ” “;
    $de = new-object directoryservices.directoryentry(“LDAP://” + $ldap);
    $ds = new-object directoryservices.directorysearcher($de);

    #805306368 = useraccount type
    $ds.filter = “(&(samaccountname=” + $account + “)(samaccounttype=805306368))”;
    $rc = $ds.findall();

    foreach($person in $rc)
    {

    echo “#################################################”;
    “@ ” + $person.properties.name;
    echo “#################################################”;
    echo “Group Membership `n——————”;

    foreach($groupName in $person.properties.memberof )
    {

    if($groupname){
    $g = $groupname.tostring();
    $g.substring(3,$g.indexof(“,”)-3);
    #$groupname ;
    }
    }

    echo ” ”
    }

  19. Here is the error that was returned to me. What am I missing?

    PS C:\> .\get-mygroupmembersrecursive.ps1
    The term ‘Get-QADGroup’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At C:\get-mygroupmembersrecursive.ps1:54 char:29
    + $ParentGroup = Get-QADGroup <<<< -Name $ParentGroupName
    + CategoryInfo : ObjectNotFound: (Get-QADGroup:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

  20. I’m trying to modify the script so it exports the members of a group to a CSV file.

    But I’m afraid I don’t know how, could someone post the code?

  21. Sorry for such a lame post, but I am a total PS noob. You say “feed it AD Group Names as a parameter” – what is the syntax you are using? I have tried everyting I can think of (and it all ends in an error at line 54,
    “Object reference not set to an instance of an object.
    At :line:54 char:28
    + $ParentGroup = Get-QADGroup <<<< -Name $ParentGroupName

  22. Hi Hugo,

    I tried your script on a large DL but it didn’t include contacts. Is there a way to include contacts and mail-enabled users as well? How about users, mail-enabled users and contacts in other domains as well?

    Thanks. I work for a non-profit that helps kids in poor neighborhoods get to and through college and we really appreciate your making this script available.

    Robert

  23. Hi

    Get-QADGroup : Cannot validate argument on parameter ‘Name’. The argument is null or empty.

    Error i got when running script?

    /T

  24. Hi,
    I’ve just downloaded the script and when I run it, some ‘group Name’ are not reported in the result. Is there difference between Local Group, Domain Group and Universal Group ?
    I tryed to put all groups in first one, no effects.
    Thanks.

  25. Hi,
    Do you have a new version of this script because, I can’see in result all Group ‘Name’. I think, the script made difference between universal, global an local group.
    I used it in 2003 AD sever.
    Thanks

  26. I have changed 31 line to display Subgroups
    highlight=” Write-Host (“{0}{1}” -f $Indent,$Object) -ForegroundColor “green” “

  27. Pavel,
    I need to Audit Shared folders for their permissions. However, I need to be able to see ALL of the child folders AND enumerate the active directory users within each group that has permission to a particular share. I would like to incorporate Get-MyGroupMembersRecursive.ps1 with the script on http://poshcode.org/1721 named Audit NTFS on Shares by DigitalAsylum. However, I am at a loss about how to feed the user group through the script. Would you be able to assist?
    Kindest regards,
    Maria

  28. I am not good in powershell as you want. I solved similar problem by this small script. It has been working quite long. Result in .txt file I opened by hand in excel.

    # START

    dir \\FileServer\Sharing\ -recurse | Where-Object { $_.PSIsContainer } |
    ForEach-Object {Get-Acl $_.FullName} |
    ForEach-Object { $_.Access `
    | Add-Member -Name PSPath -MemberType NoteProperty -Value $_.PSPath -PassThru `
    | Add-Member -Force -Name ToString -MemberType ScriptMethod -Value {“$($this
    .IdentityReference), $($this.AccessControlType), $($this.FileSystemRights)”} -PassThru
    } |
    Where-Object { $_.IsInherited -like “*False*” } |
    Format-Table -AutoSize | Out-File D:\Result.txt -encoding unicode

    # END

    The result include only non inherited permittions. You have to change name of server, sharing and path to result file.
    Best regards
    Pavel

  29. I am attempting to run a variation of this script which will get list of distribution groups, get the name of the group and its members (names and email) for part of the body of an email. And then email to each Distribution goup an email. So far I can get the groups and export-csv to remove notypeinformation and then clean up the quotes due to the export. I have part of the send-mailmessage crafted but having trouble putting all together especially getting group members per group…

    Any help would be appreciated… Thx

  30. I run this script, but I don’t know what I change next row.

    $ParentGroup = Get-QADGroup -Name $ParentGroupName

    Next error message:

    Get-QADGroup : Cannot validate argument on parameter ‘Name’. The argument is null or empty. S………

  31. This script is great. I have a few trees in our AD Forest, how can I get the members of groups in the different domains. For example I have a list of Domain Groups (i.e. DomainA\Group1
    DOmainB\Group3 …etc

    I would liek to pull the sub groups and members from those as well. Any Ideas?

    Thanks
    Magnus

Leave a Reply