When working with Active Directory administration in PowerShell, a common requirement is to list all security groups along with their members under a specific Organizational Unit (OU). The basic approach using Get-ADGroup
and Get-ADGroupMember
gives you the members, but loses the crucial group context in the output.
Here's an improved script that maintains the group-member relationship in the output:
# Specify your OU path
$OUPath = "OU=Groups,DC=corp,DC=ourcompany,DC=Com"
# Get all groups and their members with proper formatting
Get-ADGroup -Filter * -SearchBase $OUPath | ForEach-Object {
$group = $_
Write-Output ("nGroup: " + $group.Name)
Get-ADGroupMember -Identity $group | Select-Object Name, SamAccountName, objectClass
}
For larger environments, you might want to export the data to CSV:
$results = @()
$OUPath = "OU=Groups,DC=corp,DC=ourcompany,DC=Com"
Get-ADGroup -Filter * -SearchBase $OUPath | ForEach-Object {
$group = $_
Get-ADGroupMember -Identity $group | ForEach-Object {
$results += [PSCustomObject]@{
GroupName = $group.Name
MemberName = $_.Name
MemberType = $_.objectClass
SamAccountName = $_.SamAccountName
}
}
}
$results | Export-Csv -Path "ADGroupMembers.csv" -NoTypeInformation
For groups with many members (over 5000), use this optimized approach:
Get-ADGroup -Filter * -SearchBase $OUPath | ForEach-Object {
$group = $_
$members = Get-ADGroupMember -Identity $group -ErrorAction SilentlyContinue
if ($members) {
Write-Output ("nGroup: " + $group.Name + " (" + $members.Count + " members)")
$members | Select-Object -First 10 | Format-Table Name, SamAccountName
if ($members.Count -gt 10) {
Write-Output ("... plus " + ($members.Count - 10) + " more members")
}
} else {
Write-Output ("nGroup: " + $group.Name + " (Empty)")
}
}
When querying large AD environments:
- Add
-ResultPageSize 1000
toGet-ADGroup
for better performance - Consider running the script during off-peak hours
- For very large directories, process OUs separately
When working with Active Directory management in Windows Server 2008 R2, a common task is enumerating all security groups within a specific Organizational Unit (OU) along with their respective members. The basic PowerShell approach often returns just member objects without clear group association - which defeats the purpose of structured directory reporting.
# Full group membership report with OU filtering
Get-ADGroup -Filter * -SearchBase "OU=Groups,DC=corp,DC=ourcompany,DC=com" | ForEach-Object {
$group = $_
Write-Output ("nGroup: " + $group.Name)
Get-ADGroupMember -Identity $group | Select-Object name, objectClass
}
For practical enterprise use, we should add CSV export functionality:
$output = @()
$groups = Get-ADGroup -Filter * -SearchBase "OU=Groups,DC=corp,DC=ourcompany,DC=com"
foreach ($group in $groups) {
$members = Get-ADGroupMember -Identity $group -Recursive | Select-Object name, objectClass
foreach ($member in $members) {
$output += [PSCustomObject]@{
GroupName = $group.Name
MemberName = $member.name
ObjectType = $member.objectClass
}
}
}
$output | Export-Csv -Path "C:\ADGroupReport.csv" -NoTypeInformation
For domains with thousands of groups, we need performance optimizations:
# Parallel processing version for large environments
$groupPaths = @(
"OU=Groups,DC=corp,DC=ourcompany,DC=com",
"OU=Security,DC=corp,DC=ourcompany,DC=com"
)
$results = $groupPaths | ForEach-Object -Parallel {
Import-Module ActiveDirectory
$groups = Get-ADGroup -Filter * -SearchBase $_
foreach ($group in $groups) {
$members = Get-ADGroupMember -Identity $group -Recursive
foreach ($member in $members) {
[PSCustomObject]@{
GroupDN = $group.DistinguishedName
GroupName = $group.Name
MemberDN = $member.distinguishedName
MemberName= $member.name
SamAccountName = $member.SamAccountName
}
}
}
} -ThrottleLimit 10
$results | Export-CliXml -Path "C:\ParallelADReport.xml"
Sometimes we need to filter specific group types:
# Query only security groups (not distribution groups)
Get-ADGroup -Filter {GroupCategory -eq "Security"} -SearchBase "OU=Groups,DC=corp,DC=ourcompany,DC=com" |
ForEach-Object {
[PSCustomObject]@{
GroupName = $_.Name
Members = (Get-ADGroupMember $_ | Select-Object -ExpandProperty Name) -join "; "
}
} | Format-Table -AutoSize
To properly handle nested group memberships (groups within groups):
function Get-FullADGroupMembership {
param(
[Parameter(Mandatory=$true)]
[string]$GroupName
)
$members = @()
$groupMembers = Get-ADGroupMember -Identity $GroupName
foreach ($member in $groupMembers) {
if ($member.objectClass -eq "group") {
$members += Get-FullADGroupMembership -GroupName $member.SamAccountName
}
else {
$members += $member
}
}
return $members | Select-Object name, objectClass -Unique
}
# Usage example:
Get-FullADGroupMembership -GroupName "Domain Admins" | Format-Table