KMaks.ActiveDirectoryRights.psm1

function Get-ADRights {
    #Requires -Module ActiveDirectory
    Param(
        [parameter(Mandatory=$false)]
        [string]$SearchBase,

        [parameter(Mandatory=$false)]
        #[ValidateSet("computer","group","organizationalUnit","user")]
        [string]$ObjectClass,

        [parameter(Mandatory=$false)]
        [ValidateSet("Base","OneLevel","Subtree")]
        [string]$SearchScope = "Base",

        [parameter(Mandatory=$false)]
        [switch]$SkipInherited,

        [parameter(mandatory=$false)]
        [switch]$SkipBuiltInIdentities,

        [parameter(mandatory=$false)]
        [ValidateSet("Generic","SeparateValues","Binary","")]
        [string[]]$RightsFormat = "Generic"
    )

    # Check whether ActiveDirectory module is loaded
    If (-not (Get-Module -Name ActiveDirectory)) {
        Throw "This function requires ActiveDirectory module to be loaded."
    }

    # Built-In identities to skip if -SkipBuiltInIdentities switch is used
    $BuiltInIdentities = @(
        "CREATOR OWNER"
        "Everyone"

        "BUILTIN\Administrators"
        "BUILTIN\Users"
        "BUILTIN\Guests"
        "BUILTIN\Power Users"
        "BUILTIN\Account Operators"
        "BUILTIN\Server Operators"
        "BUILTIN\Print Operators"
        "BUILTIN\Backup Operators"
        "BUILTIN\Replicators"
        "BUILTIN\Pre-Windows 2000 Compatible Access"
        "BUILTIN\Remote Desktop Users"
        "BUILTIN\Network Configuration Operators"
        "BUILTIN\Incoming Forest Trust Builders"
        "BUILTIN\Performance Monitor Users"
        "BUILTIN\Performance Log Users"
        "BUILTIN\Windows Authorization Access Group"
        "BUILTIN\Terminal Server License Servers"
        "BUILTIN\Distributed COM Users"
        "BUILTIN\Cryptographic Operators"
        "BUILTIN\Event Log Readers"
        "BUILTIN\Certificate Service DCOM Access"
        "BUILTIN\RDS Remote Access Servers"
        "BUILTIN\RDS Endpoint Servers"
        "BUILTIN\RDS Management Servers"
        "BUILTIN\Hyper-V Administrators"
        "BUILTIN\Access Control Assistance Operators"
        "BUILTIN\Remote Management Users"

        "NT AUTHORITY\SELF"
        "NT AUTHORITY\SYSTEM"
        "NT AUTHORITY\Authenticated Users"
        "NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS"

        # Source: https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/security-identifiers
        "S-1-5-1"      # Dialup
        "S-1-5-113"    # Local account
        "S-1-5-114"    # Local account and member of Administrators group
        "S-1-5-2"      # Network
        "S-1-5-3"      # Batch
        "S-1-5-4"      # Interactive
        "S-1-5-6"      # Service
        "S-1-5-7"      # Anonymous Logon
        "S-1-5-8"      # Proxy
        "S-1-5-9"      # Enterprise Domain Controllers
        "S-1-5-10"     # Self
        "S-1-5-11"     # Authenticated Users
        "S-1-5-12"     # Restricted Code
        "S-1-5-13"     # Terminal Server User
        "S-1-5-14"     # Remote Interactive Logon
        "S-1-5-15"     # This Organization
        "S-1-5-17"     # IIS_USRS
        "S-1-5-18"     # System (or LocalSystem)
        "S-1-5-19"     # NT Authority (LocalService)
        "S-1-5-20"     # Network Service
        "S-1-5-32-544" # Administrators
        "S-1-5-32-545" # Users
        "S-1-5-32-546" # Guests
        "S-1-5-32-547" # Power Users
        "S-1-5-32-548" # Account Operators
        "S-1-5-32-549" # Server Operators
        "S-1-5-32-550" # Print Operators
        "S-1-5-32-551" # Backup Operators
        "S-1-5-32-552" # Replicators
        "S-1-5-32-554" # Builtin\Pre-Windows 2000 Compatible Access
        "S-1-5-32-555" # Builtin\Remote Desktop Users
        "S-1-5-32-556" # Builtin\Network Configuration Operators
        "S-1-5-32-557" # Builtin\Incoming Forest Trust Builders
        "S-1-5-32-558" # Builtin\Performance Monitor Users
        "S-1-5-32-559" # Builtin\Performance Log Users
        "S-1-5-32-560" # Builtin\Windows Authorization Access Group
        "S-1-5-32-561" # Builtin\Terminal Server License Servers
        "S-1-5-32-562" # Builtin\Distributed COM Users
        "S-1-5-32-569" # Builtin\Cryptographic Operators
        "S-1-5-32-573" # Builtin\Event Log Readers
        "S-1-5-32-574" # Builtin\Certificate Service DCOM Access
        "S-1-5-32-575" # Builtin\RDS Remote Access Servers
        "S-1-5-32-576" # Builtin\RDS Endpoint Servers
        "S-1-5-32-577" # Builtin\RDS Management Servers
        "S-1-5-32-578" # Builtin\Hyper-V Administrators
        "S-1-5-32-579" # Builtin\Access Control Assistance Operators
        "S-1-5-32-580" # Builtin\Remote Management Users
        "S-1-5-64-10"  # NTLM Authentication
        "S-1-5-64-14"  # SChannel Authentication
        "S-1-5-64-21"  # Digest Authentication
        "S-1-5-80"     # NT Service
        "S-1-5-80-0"   # All Services
        "S-1-5-83-0"   # NT VIRTUAL MACHINE\Virtual Machines
    )

    # Search GUID in the dictionary
    function Get-SchemaIdFromDictionaryByGuid ($Dictionary, $Guid) {
        $Object = $Dictionary | Where-Object GUID -eq $Guid

        If ($Object.Name) {
            Return $Object.Name
        }
        ElseIf ($Guid -eq "00000000-0000-0000-0000-000000000000") {
            Return $null
        }
        Else {
            Return $Guid
        }    
    }

    # Get AD objects
    $GetADObjectConfig = @{
        Filter = "*"
    }
    If ($SearchBase) { $GetADObjectConfig.SearchBase = $SearchBase }
    If ($SearchScope) { $GetADObjectConfig.SearchScope = $SearchScope }
    If ($ObjectClass) { $GetADObjectConfig.Filter = 'objectClass -eq "{0}"' -f $ObjectClass }
    [array]$Objects = Get-ADObject @GetADObjectConfig

    # Build a GUID Dictionary
    $GUIDDictionary = Get-ADObject -Filter 'SchemaIDGUID -like "*"' -SearchBase (Get-ADRootDSE).schemanamingContext -Properties name, schemaIDGUID |
                      Select-Object name, @{n="GUID";e={$_.schemaIDGUID -as [guid]}}
    $GUIDDictionary += Get-ADObject -Filter 'objectClass -eq "controlAccessRight"' -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).configurationNamingContext)" -Properties name, rightsGUID |
                       Select-Object name, @{n="GUID";e={$_.rightsGUID -as [guid]}}

    foreach ($Object in $Objects){
        
        # Write progress indicator
        $WriteProgressConfig = @{
            Activity = "Reading ACLs {0}/{1} ({2}%)" -f ++$i, ($Objects.Count), [math]::Round($i/($Objects.Count) * 100)
            Status = "'{0}'" -f $Object.DistinguishedName
            Id = 0
            PercentComplete = $i/($Objects.Count) * 100
        }
        Write-Progress @WriteProgressConfig

        # Get ACLs for $Object
        $Acl = Get-ACL -Path ("AD:\{0}" -f $Object.DistinguishedName)

        foreach ($Ace in $Acl.Access){
            # Skip inherited ACE if -SkipInherited switch is used
            If (
                $SkipInherited -and
                $Ace.IsInherited
            ) { Continue }
            # Skip built-in identities if -SkipBuiltInIdentities
            If (
                $SkipBuiltInIdentities -and
                $BuiltInIdentities -contains $Ace.IdentityReference
            ) { Continue }

            # Build an object to return
            $Return = [PSCustomObject]@{
                DistinguishedName       = $Object.DistinguishedName
                ObjectClass             = $Object.ObjectClass
                Identity                = $Ace.IdentityReference
                RightsType              = $Ace.AccessControlType
                Rights                  = $Ace.ActiveDirectoryRights
                InheritanceType         = $Ace.InheritanceType
                ObjectType              = Get-SchemaIdFromDictionaryByGuid -Dictionary $GUIDDictionary -Guid $Ace.ObjectType
                InheritedObjectType     = Get-SchemaIdFromDictionaryByGuid -Dictionary $GUIDDictionary -Guid $Ace.InheritedObjectType

                #GenericExecute = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::GenericExecute )
                #GenericWrite = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::GenericWrite )
                #GenericRead = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::GenericRead )
                #GenericAll = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::GenericAll )

                CreateChild             = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::CreateChild )
                DeleteChild             = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::DeleteChild )
                ListChildren            = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::ListChildren )
                Self                    = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::Self )
                ReadProperty            = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::ReadProperty )
                WriteProperty           = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty )
                DeleteTree              = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::DeleteTree )
                ListObject              = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::ListObject )
                ExtendedRight           = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight )
                Delete                  = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::Delete )
                ReadControl             = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::ReadControl )
                WriteDacl               = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::WriteDacl )
                WriteOwner              = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::WriteOwner )
                Synchronize             = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::Synchronize )
                AccessSystemSecurity    = $Ace.ActiveDirectoryRights.HasFlag( [System.DirectoryServices.ActiveDirectoryRights]::AccessSystemSecurity )

                BinaryRights            = [Convert]::ToString($Ace.ActiveDirectoryRights.value__,2).PadLeft(32,"0")
                IsInherited             = $Ace.IsInherited
            }

            $ReturnProperties = [System.Collections.ArrayList]::new()
            [void]$ReturnProperties.AddRange(
                @(
                    'DistinguishedName'
                    'ObjectClass'
                    'Identity'
                    'RightsType'
                    'InheritanceType'
                    'ObjectType'
                    'InheritedObjectType'
                )
            )
            If ($ObjectClass) {
                [void]$ReturnProperties.Remove('ObjectClass')
            }
            If (-not $SkipInherited) {
                [void]$ReturnProperties.Add('IsInherited')
            }
            $RightsIndex = 3
            switch ($RightsFormat)
            {
                'Binary' {
                    [void]$ReturnProperties.InsertRange(
                        $RightsIndex,
                        @(
                            'BinaryRights'
                        )
                    )
                }
                'Generic' {
                    [void]$ReturnProperties.InsertRange(
                        $RightsIndex,
                        @(
                            'Rights'
                        )
                    )
                }
                'SeparateValues' {
                    [void]$ReturnProperties.InsertRange(
                        $RightsIndex,
                        @(
                            'CreateChild'
                            'DeleteChild'
                            'ListChildren'
                            'Self'
                            'ReadProperty'
                            'WriteProperty'
                            'DeleteTree'
                            'ListObject'
                            'ExtendedRight'
                            'Delete'
                            'ReadControl'
                            'WriteDacl'
                            'WriteOwner'
                            'Synchronize'
                            'AccessSystemSecurity'
                        )
                    )
                }
            }
            $Return | Select-Object -Property $ReturnProperties
        }
    }
}