Private/Test/Test-IsBA.ps1

function Test-IsBA {
    <#
        .SYNOPSIS
        Tests if a principal is a member of the BUILTIN\Administrators group.
 
        .DESCRIPTION
        Checks if the specified principal (or current user if not specified) is a member of
        the BUILTIN\Administrators group (S-1-5-32-544) by querying Active Directory and
        checking both direct and nested group membership using the tokenGroups attribute.
         
        The BUILTIN\Administrators group (S-1-5-32-544) is a well-known local group that
        exists on every domain controller and member computer. This function checks membership
        across all domains in the forest to support multi-domain environments.
         
        The function performs efficient membership checks by:
        1. First checking direct membership in the Administrators group
        2. Then using the tokenGroups constructed attribute for nested membership detection
        3. Searching across all domains in the forest for comprehensive coverage
 
        .PARAMETER IdentityReference
        The IdentityReference (SID or NTAccount) to check for Administrators membership.
        If not specified, checks the current user.
 
        .PARAMETER Credential
        PSCredential for authenticating to Active Directory. Required for LDAP queries.
 
        .PARAMETER RootDSE
        A DirectoryEntry object for the RootDSE. Used to determine forest domains for LDAP queries.
 
        .INPUTS
        System.Security.Principal.IdentityReference
        You can pipe IdentityReference objects to this function.
 
        .OUTPUTS
        System.Boolean
        Returns $true if the principal is a member (direct or nested) of the BUILTIN\Administrators group.
        Returns $false otherwise.
 
        .EXAMPLE
        Test-IsBA -IdentityReference $sid -Credential $cred -RootDSE $rootDSE
        Checks if the specified SID is a member of BUILTIN\Administrators in any domain.
 
        .EXAMPLE
        $ace.IdentityReference | Test-IsBA -Credential $cred -RootDSE $rootDSE
        Checks if an ACE identity is a member of BUILTIN\Administrators.
 
        .EXAMPLE
        if (Test-IsBA -IdentityReference $userSid -Credential $cred -RootDSE $rootDSE) {
            Write-Host "User has Administrator privileges"
        }
        Conditionally executes code based on Administrators group membership.
 
        .EXAMPLE
        Test-IsBA -IdentityReference $sid -Credential $cred -RootDSE $rootDSE -Verbose
        Checks membership with verbose output showing whether membership is direct or nested.
 
        .NOTES
        Well-known SID checked:
        - S-1-5-32-544: BUILTIN\Administrators
         
        This function checks all domains in the forest to support multi-domain environments.
        Verbose output indicates whether membership is DIRECT or NESTED.
         
        The tokenGroups attribute is a constructed attribute that contains all security groups
        (direct and nested) that the principal is a member of, making nested membership
        detection efficient without manual recursion.
 
        .LINK
        https://learn.microsoft.com/en-us/windows/win32/secauthz/well-known-sids
         
        .LINK
        https://learn.microsoft.com/en-us/windows/win32/adschema/a-tokengroups
    #>

    [CmdletBinding()]
    [OutputType([bool])]
    param (
        [Parameter(ValueFromPipeline)]
        [System.Security.Principal.IdentityReference]
        $IdentityReference,

        [Parameter(Mandatory)]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter(Mandatory)]
        [System.DirectoryServices.DirectoryEntry]
        $RootDSE
    )

    #requires -Version 5.1

    process {
        try {
            # If no identity specified, use current user
            if (-not $IdentityReference) {
                $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
                $IdentityReference = $identity.User
                Write-Verbose "No identity specified, checking current user: $($IdentityReference.Value)"
            }

            # Convert to SID - Convert-IdentityReferenceToSid handles all the complexity
            $sid = $IdentityReference | Convert-IdentityReferenceToSid
            if (-not $sid) {
                Write-Warning "Could not resolve identity to SID: $IdentityReference"
                return $false
            }

            Write-Verbose "Checking if SID $($sid.Value) is member of domain Administrators groups"

            # Extract server from RootDSE
            if ($RootDSE.Path -match 'LDAP://([^/]+)') {
                $server = $Matches[1]
            } else {
                Write-Warning "Could not extract server from RootDSE path."
                return $false
            }

            # Get all domain partitions in the forest using Global Catalog
            $configNC = $RootDSE.configurationNamingContext.Value
            $rootDomainDN = $RootDSE.rootDomainNamingContext.Value
            
            # Query for all crossRef objects to find all domains
            $partitionsPath = "LDAP://$server/CN=Partitions,$configNC"
            $partitionsEntry = New-AuthenticatedDirectoryEntry -Path $partitionsPath
            
            $partitionsSearcher = New-Object System.DirectoryServices.DirectorySearcher
            $partitionsSearcher.SearchRoot = $partitionsEntry
            $partitionsSearcher.Filter = "(&(objectClass=crossRef)(systemFlags:1.2.840.113556.1.4.803:=2))"
            $partitionsSearcher.PropertiesToLoad.AddRange(@('nCName')) | Out-Null
            $partitionsSearcher.SearchScope = [System.DirectoryServices.SearchScope]::OneLevel
            
            $allPartitions = $partitionsSearcher.FindAll()
            
            # Check each domain for Administrators group membership
            foreach ($partition in $allPartitions) {
                if ($partition.Properties['nCName'].Count -gt 0) {
                    $domainDN = $partition.Properties['nCName'][0]
                    Write-Verbose "Checking domain: $domainDN"
                    
                    # The Administrators group is always S-1-5-32-544 (BUILTIN\Administrators)
                    # This is a well-known SID that exists in every domain
                    $adminGroupSid = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544')
                    
                    Write-Verbose "Administrators group SID: $($adminGroupSid.Value)"
                    
                    # Search for the Administrators group and check membership
                    $domainPath = "LDAP://$server/$domainDN"
                    $domainEntry = New-AuthenticatedDirectoryEntry -Path $domainPath
                    
                    $groupSearcher = New-Object System.DirectoryServices.DirectorySearcher
                    $groupSearcher.SearchRoot = $domainEntry
                    $groupSearcher.Filter = "(objectSid=$($adminGroupSid.Value))"
                    $groupSearcher.PropertiesToLoad.AddRange(@('member')) | Out-Null
                    $groupSearcher.SearchScope = [System.DirectoryServices.SearchScope]::Subtree
                    
                    $groupResult = $groupSearcher.FindOne()
                    
                    if ($groupResult) {
                        # Use tokenGroups attribute for recursive membership check
                        # This is more efficient than manually recursing through groups
                        Write-Verbose "Found Administrators group, checking membership recursively"
                        
                        # First check for direct membership
                        $members = $groupResult.Properties['member']
                        $isDirectMember = $false
                        
                        foreach ($memberDN in $members) {
                            # Get the member's SID
                            $memberPath = "LDAP://$server/$memberDN"
                            $memberEntry = New-AuthenticatedDirectoryEntry -Path $memberPath
                            
                            if ($memberEntry.Properties['objectSid'].Count -gt 0) {
                                $memberSidBytes = $memberEntry.Properties['objectSid'][0]
                                $memberSid = New-Object System.Security.Principal.SecurityIdentifier($memberSidBytes, 0)
                                
                                if ($memberSid.Value -eq $sid.Value) {
                                    $isDirectMember = $true
                                    $memberEntry.Dispose()
                                    break
                                }
                            }
                            
                            $memberEntry.Dispose()
                        }
                        
                        # Search for the user/group object by SID
                        $userSearcher = New-Object System.DirectoryServices.DirectorySearcher
                        $userSearcher.SearchRoot = $domainEntry
                        $userSearcher.Filter = "(objectSid=$($sid.Value))"
                        $userSearcher.PropertiesToLoad.AddRange(@('distinguishedName')) | Out-Null
                        $userSearcher.SearchScope = [System.DirectoryServices.SearchScope]::Subtree
                        
                        $userResult = $userSearcher.FindOne()
                        
                        if ($userResult) {
                            # Get the DirectoryEntry for the user to access tokenGroups
                            $userEntry = $userResult.GetDirectoryEntry()
                            $userEntry.RefreshCache(@('tokenGroups'))
                            
                            if ($userEntry.Properties['tokenGroups'].Count -gt 0) {
                                # tokenGroups contains all groups (direct and nested) the user is a member of
                                foreach ($tokenGroupBytes in $userEntry.Properties['tokenGroups']) {
                                    $tokenGroupSid = New-Object System.Security.Principal.SecurityIdentifier($tokenGroupBytes, 0)
                                    
                                    if ($tokenGroupSid.Value -eq $adminGroupSid.Value) {
                                        if ($isDirectMember) {
                                            Write-Verbose "SID $($sid.Value) is a DIRECT member of Administrators in $domainDN"
                                        } else {
                                            Write-Verbose "SID $($sid.Value) is a NESTED member of Administrators in $domainDN"
                                        }
                                        
                                        # Cleanup
                                        $userEntry.Dispose()
                                        $userSearcher.Dispose()
                                        $groupSearcher.Dispose()
                                        $domainEntry.Dispose()
                                        $allPartitions.Dispose()
                                        $partitionsSearcher.Dispose()
                                        $partitionsEntry.Dispose()
                                        
                                        return $true
                                    }
                                }
                                Write-Verbose "SID $($sid.Value) is NOT a member of Administrators in $domainDN"
                            } else {
                                Write-Verbose "tokenGroups attribute is empty for SID $($sid.Value) in $domainDN"
                            }
                            
                            $userEntry.Dispose()
                        } else {
                            Write-Verbose "Could not find user object for SID $($sid.Value) in $domainDN"
                        }
                        
                        $userSearcher.Dispose()
                    }
                    
                    $groupSearcher.Dispose()
                    $domainEntry.Dispose()
                }
            }
            
            # Cleanup
            $allPartitions.Dispose()
            $partitionsSearcher.Dispose()
            $partitionsEntry.Dispose()
            
            Write-Verbose "SID $($sid.Value) is NOT a member of domain Administrators in any domain"
            return $false
            
        } catch {
            $errorRecord = [System.Management.Automation.ErrorRecord]::new(
                $_.Exception,
                'AdministratorsCheckFailed',
                [System.Management.Automation.ErrorCategory]::InvalidOperation,
                $IdentityReference
            )
            $PSCmdlet.WriteError($errorRecord)
            return $false
        }
    }
}