Not able to get the count of Nested Members in AD Group

Hi Team,

I am trying to get the count of the total members of AD Groups in particular OU. These groups contain some nested groups as well. I am not able to get the exact count, in some groups, I am getting a blank, when I checked them individually, I found there are some members present. Also, there are some nested groups as well inside those groups, my code is not able to display them as well. I am pasting the code below, kindly suggest some modification (Don’t want to change the whole code :)):

$a = Get-ADGroup -Filter * | where {$.distinguishedname -like ‘somegroup’}
$b = $a.name
foreach ($ab in $b)
{
Get-ADGroupMember $ab| where objectclass -EQ “group” | select name, @{n=‘Total Members’; e={[string](Get-ADGroupMember -Identity "$
" -Recursive).count}}, @{n=‘Canonical Name’; e={Get-ADGroup $_ -properties CanonicalName}}
}

Thanks,

Hi

Following is ugly, but basically does what you need… :smiley:

Function Get-NestedGroup {
    param([string]$name)
    [PSCustomObject]@{
        Parent = $name
        Child = $null
        ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
    }
    $Parent = $name
    Get-ADGroup -Identity $name | Get-ADGroupMember | where {$_.objectClass -eq 'Group'} | ForEach {
        
        $name = $_.name
        If (Get-ADGroup -Identity $name | Get-ADGroupMember | where {$_.objectClass -eq 'Group'}) {
        Get-NestedGroup -name $name

        #if group does have groups
        [PSCustomObject]@{
            Parent = $Parent
            Child = $name
            ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
        }

        } Else {
        #if group does not have groups
        [PSCustomObject]@{
            Parent = $Parent
            Child = $name
            ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
        }
        }
    }
}

Get-NestedGroup -name 'group1' | Sort Parent

Output is following:

Parent Child  ChildGroupCount
------ -----  ---------------
group1                      2
group1 Group3               1
group1 Group2               0
Group3                      1
Group3 Group4               1
Group4                      1
Group4 Group5               0

Regards

Jake

Hi

Basicly this does what you need, not pretty but…

$global:collection = New-Object System.Collections.Generic.List[System.Object]

Function Get-NestedGroup {

    param([string]$name)

    $collection.add([PSCustomObject]@{
        Parent = $name
        Child = $null
        ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
    })

    $Parent = $name

    Get-ADGroup -Identity $name | Get-ADGroupMember | where {$_.objectClass -eq 'Group'} | ForEach {
        
        $name = $_.name

        $collection.add([PSCustomObject]@{
            Parent = $Parent
            Child = $name
            ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
        })

        If ($Global:collection.Parent -match $name) {continue}

        Get-NestedGroup -name $name
        
    }
}

Get-NestedGroup -name 'group1'
$global:collection | sort parent

Output is following:

Parent Child  ChildGroupCount
------ -----  ---------------
group1                      2
group1 Group3               1
group1 Group2               0
Group2                      0
Group3                      1
Group3 Group4               1
Group4                      1
Group4 Group5               1
Group5                      1
Group5 Group1               2

edit. This becomes perpetual motion machine when Group1 was member of Group5. So not working as it should.
edit2. Thanks to Aapeli Hietikko for pointing the $global:collection. Manager to resolve the perpetual motion machine and it skips if the child group is already found as parent.

Regards

Jake

Hi

Basicly this does what you need, not pretty but…

$global:collection = New-Object System.Collections.Generic.List[System.Object]

Function Get-NestedGroup {

    param([string]$name)

    $collection.add([PSCustomObject]@{
        Parent = $name
        Child = $null
        ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
    })

    $Parent = $name

    Get-ADGroup -Identity $name | Get-ADGroupMember | where {$_.objectClass -eq 'Group'} | ForEach {
        
        $name = $_.name

        $collection.add([PSCustomObject]@{
            Parent = $Parent
            Child = $name
            ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
        })

        If ($Global:collection.Parent -match $name) {continue}

        Get-NestedGroup -name $name
        
    }
}

Get-NestedGroup -name 'group1'
$global:collection | sort parent

Output is following:

Parent Child  ChildGroupCount
------ -----  ---------------
group1                      2
group1 Group3               1
group1 Group2               0
Group2                      0
Group3                      1
Group3 Group4               1
Group4                      1
Group4 Group5               1
Group5                      1
Group5 Group1               2

edit. This becomes perpetual motion machine when Group1 was member of Group5. So not working as it should.
edit2. Thanks to Aapeli Hietikko for pointing the $global:collection. Manager to resolve the perpetual motion machine and it skips if the child group is already found as parent.
edit3. Seems like I have modified this too many times, sorry admins!

Regards

Jake

Hi

Forgot the canonical name, so here you go.

$global:collection = New-Object System.Collections.Generic.List[System.Object]

Function Get-NestedGroup {

    param([string]$name)

    $collection.add([PSCustomObject]@{
        Parent = $name
        Child = $null
        ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
        "Canonical Name" = (Get-ADGroup $name -properties CanonicalName).canonicalname
    })

    $Parent = $name

    Get-ADGroup -Identity $name | Get-ADGroupMember | where {$_.objectClass -eq 'Group'} | ForEach {
        
        $name = $_.name

        $collection.add([PSCustomObject]@{
            Parent = $Parent
            Child = $name
            ChildGroupCount = Get-ADGroupMember -Identity $name | measure | select -ExpandProperty count
            "Canonical Name" = (Get-ADGroup $name -properties CanonicalName).canonicalname
        })

        If ($Global:collection.Parent -match $name) {continue}

        Get-NestedGroup -name $name
        
    }
}

Get-NestedGroup -name 'group1'
$global:collection | sort parent

Regards

Jake

There are lots of examples, some fully built that handle this exact use case. Here are a few from my OneNote library have had for a few years on this topic.

Token Bloat Troubleshooting by Analyzing Group Nesting in AD

This tool started when I was finding ways to analyze the complexity of group memberships in AD. Other than the usual average/median/min/max of number of members, number of memberships etc, I was also interested in finding out the maximum nesting levels of groups and the recursive group membership count. For e.g. in the diagram below, the maximum nesting level of ‘group a’ is 3 and its recursive group membership count is 6.

Token Bloat Troubleshooting by Analyzing Group Nesting in AD | Microsoft Learn

Get nested group membership - function
This function will recursively enumerate members of a given group along with nesting level and parent group information. If there is a circular membership, it will be displayed in Comment column.It accepts input from pipeline and works well with get-adgroup.

Browse code samples | Microsoft Learn

How To Find Nested Active Directory Group Memberships in PowerShell

How To Find Nested Active Directory Group Memberships in PowerShell -- Redmondmag.com

Get AD Nested Group Members with Powershell
This article helps you to query nested AD group members using powershell. We can get group members by using the Active Directory powershell cmlet Get-ADGroupMember. The Get-ADGroupMember cmdlet provides the option to get all the nested group members by passing the parameter -Recursive. This powershell script also handles circular membership (infinite loop) problem.
Get AD Nested Group Members with Powershell - MorganTechSpace

How to find and report nested groups in Active Directory using PowerShell

How to find and report nested groups in Active Directory using PowerShell | vHomeLab

PowerShell Problem Solver: Enumerating Members of Large Active Directory Groups

petri.com/enumerating-members-of-large-active-directory-groups

this is what I was looking for. Thanks a ton mate. You were such a sport. :slight_smile: