Public/05_AD_User_Health/Get-VBADGroupsWithMemberCount.ps1

# ============================================================
# FUNCTION : Get-VBADGroupsWithMemberCount
# VERSION : 1.0.2
# CHANGED : 10-04-2026 -- Initial VB-compliant release
# AUTHOR : Vibhu Bhatnagar
# PURPOSE : Get Active Directory groups with member count
# ENCODING : UTF-8 with BOM
# ============================================================

<#
.SYNOPSIS
    Get Active Directory groups with member count excluding defaults.
.DESCRIPTION
    Queries Active Directory for all groups and returns their member counts,
    excluding default system groups and built-in groups. Results are sorted by
    member count for easy identification of empty or large groups.
.PARAMETER ComputerName
    Domain Controller to query. Defaults to local machine. Accepts pipeline input.
.PARAMETER Credential
    Alternate credentials for the AD query.
.EXAMPLE
    Get-VBADGroupsWithMemberCount
.EXAMPLE
    Get-VBADGroupsWithMemberCount -ComputerName DC01
.EXAMPLE
    'DC01' | Get-VBADGroupsWithMemberCount -Credential (Get-Credential)
.OUTPUTS
    [PSCustomObject]: ComputerName, SamAccountName, MemberCount, Created, Modified, Status, CollectionTime
.NOTES
    Version : 1.0.2
    Author : Vibhu Bhatnagar
    Modified : 10-04-2026
    Category : AD User Health
#>


function Get-VBADGroupsWithMemberCount {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('Name', 'Server', 'Host')]
        [string[]]$ComputerName = $env:COMPUTERNAME,
        [PSCredential]$Credential
    )
    begin {
        Import-Module ActiveDirectory -ErrorAction Stop
    }


    process {
        foreach ($computer in $ComputerName) {
            try {
                # Step 1 -- Define excluded default groups
                $excludeGroups = @(
                    'Domain Admins', 'Domain Users', 'Domain Guests', 'Enterprise Admins', 'Schema Admins',
                    'Administrators', 'Users', 'Guests', 'Account Operators', 'Backup Operators',
                    'Print Operators', 'Server Operators', 'Replicator', 'DnsAdmins', 'DnsUpdateProxy',
                    'Cert Publishers', 'Read-only Domain Controllers', 'Group Policy Creator Owners',
                    'Access Control Assistance Operators', 'ADSyncBrowse', 'ADSyncOperators', 'ADSyncPasswordSet',
                    'Allowed RODC Password Replication Group', 'Certificate Service DCOM Access', 'Cloneable Domain Controllers',
                    'Cryptographic Operators', 'DHCP Administrators', 'DHCP Users', 'Distributed COM Users',
                    'Enterprise Key Admins', 'Enterprise Read-only Domain Controllers', 'Event Log Readers', 'Hyper-V Administrators',
                    'Incoming Forest Trust Builders', 'Key Admins', 'Network Configuration Operators', 'Office 365 Public Folder Administration',
                    'Performance Log Users', 'Performance Monitor Users', 'Protected Users', 'RAS and IAS Servers',
                    'RDS Endpoint Servers', 'RDS Management Servers', 'RDS Remote Access Servers', 'Remote Management Users',
                    'Storage Replica Administrators'
                )

                # Step 2 -- Build AD query parameters
                $AdParams = @{
                    Filter     = '*'
                    Properties = 'whenCreated', 'whenChanged'
                }
                if ($computer -ne $env:COMPUTERNAME) {
                    $AdParams['Server'] = $computer
                }
                if ($Credential) {
                    $AdParams['Credential'] = $Credential
                }

                # Step 3 -- Get all non-default groups
                $allGroups = Get-ADGroup @AdParams | Where-Object { $excludeGroups -notcontains $_.Name }

                # Step 4 -- Count members in each group
                foreach ($group in $allGroups) {
                    try {
                        $GroupMemberParams = @{
                            Identity      = $group.DistinguishedName
                            ErrorAction   = 'SilentlyContinue'
                        }
                        if ($computer -ne $env:COMPUTERNAME) {
                            $GroupMemberParams['Server'] = $computer
                        }
                        if ($Credential) {
                            $GroupMemberParams['Credential'] = $Credential
                        }

                        $members = Get-ADGroupMember @GroupMemberParams
                        $memberCount = if ($members) { $members.Count } else { 0 }

                        [PSCustomObject]@{
                            ComputerName   = $computer
                            SamAccountName = $group.SamAccountName
                            MemberCount    = $memberCount
                            Created        = $group.whenCreated
                            Modified       = $group.whenChanged
                            Status         = 'Success'
                            CollectionTime = (Get-Date).ToString('dd-MM-yyyy HH:mm:ss')
                        }
                    }
                    catch {
                        [PSCustomObject]@{
                            ComputerName   = $computer
                            SamAccountName = $group.SamAccountName
                            MemberCount    = $null
                            Created        = $group.whenCreated
                            Modified       = $group.whenChanged
                            Error          = $_.Exception.Message
                            Status         = 'Failed'
                            CollectionTime = (Get-Date).ToString('dd-MM-yyyy HH:mm:ss')
                        }
                    }
                }
            }
            catch {
                [PSCustomObject]@{
                    ComputerName   = $computer
                    SamAccountName = $null
                    MemberCount    = $null
                    Created        = $null
                    Modified       = $null
                    Error          = $_.Exception.Message
                    Status         = 'Failed'
                    CollectionTime = (Get-Date).ToString('dd-MM-yyyy HH:mm:ss')
                }
            }
        }
    }
}