
close
close
Chance to win $250 in Petri 2023 Audience Survey
In a recent PowerShell Problem Solver article I demonstrated how you can use PowerShell to enumerate members of an Active Directory group. I believe that for most of you the code samples in that article will suffice. But as I pointed out at the end of the article, there is a potential issue with very large groups.
A large group will be anything with more than 5000 members. It is still possible to enumerate these groups, but it will take a few extra steps. We will still be using the Active Directory cmdlets, but we will need to process the group members individually, especially if you want to recurse through any nested groups. I’m going to demonstrate with a group called Test Group 1 that I know has more than 5000 members, including a few nested groups.
Get-adgroup 'Test Group 1' –properties Member | select –expandproperty Member | measure-object
Enumerating members of large Active Directory groups in Windows PowerShell. (Image Credits: Jeff Hicks)
Error with the Get-ADGroupmember cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)
Function Get-MyLargeGroup { [cmdletbinding()] Param( [Parameter(Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName)] [ValidateNotNullorEmpty()] [string]$Name) Begin { Write-Verbose "Starting $($MyInvocation.MyCommand)" } #begin Process { Write-Verbose "Retrieving members from $Name" $mygroup = Get-ADGroup -Identity $Name -Properties Members foreach ($member in $mygroup.members) { $object = $member | Get-ADObject -Properties samaccountname if ($object.ObjectClass -eq 'Group') { Write-Verbose "Found nested group $($object.distinguishedname)" #recursively run this command for the nested group & $MyInvocation.MyCommand -name $object.Name } else { Select-Object -InputObject $object -property ObjectClass,Name,SamAccountname,DistinguishedName } } #foreach } #process End { Write-Verbose "Ending $($MyInvocation.MyCommand)" } #end } #end function
The function takes the name of a group and retrieves the group along with its Members property. This will be a collection of distinguishednames for ever member. It might be a user, a computer or another group. I can use Get-ADObject to retrieve the member from Active Directory.
$object = $member | Get-ADObject -Properties samaccountname
All members of a group will have a samaccountname property, so I’ll grab that as well. From here I can check the object class to determine if it is a user, computer or another group. If it is a group then I can recursively call the function and enumerate the nested group. Otherwise, I’ll select some properties from the user or computer object.
if ($object.ObjectClass -eq 'Group') {
Write-Verbose "Found nested group $($object.distinguishedname)"
#recursively run this command for the nested group
& $MyInvocation.MyCommand -name $object.Name
}
else {
Select-Object -InputObject $object -property ObjectClass,Name,SamAccountname,DistinguishedName
}
I called the function Get-MyLargeGroup, but you can name it anything you want. To use, simply specify the name of a group.
Using the Get-MyLargeGroup function in Windows PowerShell. (Image Credit: Jeff Hicks)
The function found 5021 members. (Image Credit: Jeff Hicks)
>$r3 = $r2 | Select-Object * -Unique
New result number with duplicates filtered out. (Image Credit: Jeff Hicks)
$r3 | Out-Gridview -Title "Test Group 1 Members"
Final results of our test group. (Image Credits: Jeff Hicks)
$r3 | export-csv c:\work\Test-Group-1.csv -NoTypeInformation
I can use this function actually for any size group and come up with a one line command to export group members to a CSV file.
Get-MyLargeGroup -Name "Chicago Engineering" | Select * -unique | sort name | export-csv c:\work\engineering.csv -NoTypeInformation
There won’t be any Groups in the output because they were enumerated. But there could be computer accounts and perhaps you only really care about user accounts. Here’s an example of what I’m talking about.
To filter them out I could simply pipe to Where object.
Filtering using the where object in Windows PowerShell. (Image Credit: Jeff Hicks)
Function Get-MyLargeGroup2 { [cmdletbinding()] Param( [Parameter(Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName)] [ValidateNotNullorEmpty()] [string]$Name, [string[]]$Properties = @("SamAccountname","Title","Description","Department") ) Begin { Write-Verbose "Starting $($MyInvocation.MyCommand)" #add default properties $Properties += "ObjectClass" $Properties += "Name" $Properties += "DistinguishedName" Write-verbose "retrieving these user properties" Write-Verbose ( $Properties -join "," | Out-String) } #begin Process { Write-Verbose "Retrieving members from $Name" $mygroup = Get-ADGroup -Identity $Name -Properties Members foreach ($member in $mygroup.members) { $object = $member | Get-ADObject -Properties $properties if ($object.ObjectClass -eq 'Group') { Write-Verbose "Found nested group $($object.distinguishedname)" #recursively run this command for the nested group & $MyInvocation.MyCommand -name $object.Name } elseif ($object.objectclass -eq 'User') { Select-Object -InputObject $object -property $Properties } } #foreach } #process End { Write-Verbose "Ending $($MyInvocation.MyCommand)" } #end } #end function
This version includes a parameter to specify additional user properties. In the Begin scriptblock, I add some standard properties.
Now, the only output from the function is if the object is a user.
elseif ($object.objectclass -eq 'User') {
Select-Object -InputObject $object -property $Properties
}
Again, I can use this for any size group.
Get-mylargegroup2 "Project Black" | out-gridview –title "Project Black"
Now you should have several ways to enumerate members of an Active Directory group. No matter how you enumerate the group, exporting the results to a CSV or XML file is all the same, That’s the great thing about PowerShell: learn the basics once and apply it everywhere.
More in Active Directory
Microsoft Releases Update to Streamline Exchange Online License Assignments
Jan 24, 2023 | Rabia Noureen
How to Export Active Directory Users to CSV With PowerShell and ADUC
Jan 23, 2023 | Michael Reinders
ManageEngine ADSelfService Plus: Protect On-Premises and Cloud Services from Password Attacks with Multi-factor Authentication
Jan 12, 2023 | Michael Reinders
Microsoft 365 to Launch New $1.99/Month Basic Subscription with 100 GB of OneDrive Storage
Jan 11, 2023 | Rabia Noureen
Most popular on petri