PowerShell: How to List All Active Directory Groups with Members Under a Specific OU in Windows Server 2008 R2


3 views

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 to Get-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