KMaks.ActiveDirectoryRights.psm1
<#
.SYNOPSIS Get ACLs for ActiveDirectory objects. .DESCRIPTION This function can audit access rights on Active Directory objects. .PARAMETER SearchBase Specifies an Active Directory path to search. If you do not provide this parameter it will search the entire domain. .PARAMETER ObjectClass .PARAMETER SearchScope Specifies the scope of an Active Directory search. The acceptable values for this parameter are: - Base - OneLevel - Subtree A Base query searches only the current path or object. A OneLevel query searches the immediate children of that path or object. A Subtree query searches the current path or object and all children of that path or object. .PARAMETER SkipInherited Skips rights that are not sed directly but instead are inherited. .PARAMETER SkipBuiltInIdentities Skips a set of built-in identities for readability. .PARAMETER IncludeCanonicalName Includes CanonicalName for better readability for less technical users. .PARAMETER IncludeObjectOwner Includes the owner of each object. .PARAMETER RightsFormat Output format for permissions. Acceptable values for this parameter are: - Binary - Generic - SeparateValues This parameter accepts multiple values. A Generic format is a string with all the rights as returned by Get-Acl. Binary is a shorter version with binary flags that are easier to parse by external tools. SeparateValues outputs a separate column for each right with either true or false value which helps in filtering output with external tools like Microsoft Excel. .EXAMPLE # Get Access Rights on domain root Get-ADRights .EXAMPLE # Get Access Rights on a specific Organizational Unit Get-ADRights -SearchBase 'OU=Specific OU,DC=contoso,DC=com' .EXAMPLE # Get Access Rights on a specific Organizational Unit and all descendents Get-ADRights -SearchBase 'OU=Specific OU,DC=contoso,DC=com' -SearchScope Subtree .EXAMPLE # Get Access Rights on a specific Organizational Unit skipping well known built-in identities Get-ADRights -SearchBase 'OU=Specific OU,DC=contoso,DC=com' -SearchScope Subtree -SkipBuiltInIdentities .EXAMPLE # Get Access Rights on an entire domain skipping all inherited ones to determine where are they set specifically Get-ADRights -SearchBase 'OU=Specific OU,DC=contoso,DC=com' -SearchScope Subtree -SkipBuiltInIdentities -SkipInherited .EXAMPLE # Get Access Rights on an entire domain export it to CSV. Get-ADRights -SearchBase 'OU=Specific OU,DC=contoso,DC=com' -SearchScope Subtree -SkipBuiltInIdentities -SkipInherited | Export-Csv -Path "ADAccessRights.csv" #> function Get-ADRights { #Requires -Module ActiveDirectory [CmdletBinding(HelpUri = 'https://www.powershellgallery.com/packages/KMaks.ActiveDirectoryRights')] Param( [parameter(Mandatory=$false)] [string]$SearchBase, [parameter(Mandatory=$false)] [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)] [switch]$IncludeCanonicalName, [parameter(mandatory=$false)] [switch]$IncludeObjectOwner, [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 CanonicalName If ($IncludeCanonicalName) { $CanonicalName = $Object.DistinguishedName -replace ',?DC=.*$' -replace '\w{2}=' -split ',' [array]::Reverse($CanonicalName) $CanonicalName = "/{0}" -f ($CanonicalName -join '/') } # Build an object to return $Return = [PSCustomObject]@{ DistinguishedName = $Object.DistinguishedName CanonicalName = $CanonicalName ObjectClass = $Object.ObjectClass Identity = $Ace.IdentityReference ObjectOwner = $Acl.Owner 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') } If ($IncludeCanonicalName) { [void]$ReturnProperties.Insert(0, 'CanonicalName') } If ($IncludeObjectOwner) { [void]$ReturnProperties.Insert(2, 'ObjectOwner') } $InsertIndex = 4 switch ($RightsFormat) { 'Binary' { [void]$ReturnProperties.InsertRange( $InsertIndex, @( 'BinaryRights' ) ) } 'Generic' { [void]$ReturnProperties.InsertRange( $InsertIndex, @( 'Rights' ) ) } 'SeparateValues' { [void]$ReturnProperties.InsertRange( $InsertIndex, @( 'CreateChild' 'DeleteChild' 'ListChildren' 'Self' 'ReadProperty' 'WriteProperty' 'DeleteTree' 'ListObject' 'ExtendedRight' 'Delete' 'ReadControl' 'WriteDacl' 'WriteOwner' 'Synchronize' 'AccessSystemSecurity' ) ) } } $Return | Select-Object -Property $ReturnProperties } } } |