ADACLScanner is a PowerShell tool, created by Robin Granberg (formerly a PFE at Microsoft and now at Semperis). The tool can be accessed on https://github.com/canix1/ADACLScanner
It's designed to audit Active Directory permissions, export them in CSV/HTML formats, compare them to a previous export or another domain, or to default permissions. The tool also provides features to know the permissions of a user or group, identify the owner of an object, the date of the last rights modification, inherited rights, and much more.
It can be used via a graphical interface (GUI) or command line. The project is ongoing, and Robin is committed to fixing errors reported via Github.
Command Line Usage
-RecursiveFind
This parameter searches all nested groups to display all security principals having access.
-RecursiveObjectType
This parameter filters nested groups to only display users who have access.
-FilterTrustee
ACL filter for matching strings in Trustee.
-Owner
To obtain the owners.
Search examples
Custom ACLs on all OUs and containers
$res = .\ADACLScan.ps1 -Base (Get-ADRootDSE).defaultNamingContext -Scope subtree -Filter "(|(objectClass=organizationalUnit)(objectClass=container))" -SkipDefaults -ShowCriticalityColor -Output HTML -Show
# To view the result and exlucde groupPolicyContainer
$res | Where-Object ObjectClass -ne 'groupPolicyContainer'
AdminSDHolder ACL and last modified date
.\ADACLScan.ps1 -Base "CN=AdminSDHolder,CN=System,$((Get-ADRootDSE).defaultNamingContext)" -SDDate -ShowCriticalityColor -Show -Output HTML
Obtain rights for a specific user/group
.\ADACLScan.ps1 -Base (Get-ADRootDSE).defaultNamingContext -Scope subtree -Filter "(|(objectClass=organizationalUnit)(objectClass=container))" -SkipDefaults -SkipBuiltIn -ShowCriticalityColor -Output HTML -Show -EffectiveRightsPrincipal domain\user
GPO rights
.\ADACLScan.ps1 -GPO -Scope subtree -ShowCriticalityColor -Output HTML -Show -RecursiveFind
Get owners
.\ADACLScan.ps1 -Base (Get-ADRootDSE).defaultNamingContext -Owner -Scope subtree -Filter '(objectClass=*)' | Where-Object {$_.Access -eq 'Owner'}
Get Deny permissions
Search for permissions Deny
(can be useful for checking ManagedBy
or other useful hidden attributes).
.\ADACLScan.ps1 -Base (Get-ADRootDSE).defaultNamingContext -Scope subtree -Filter '(objectClass=*)' | Where-Object {$_.Access -eq 'Deny'}
Unresolved SIDs - all naming context and proprietary naming
⚠️ Execution time depends on number of objects⚠️
[System.Collections.Generic.List[PSObject]]$unresolvedSIDArray = @()
foreach($nc in (Get-ADRootDSE).namingcontexts){
$unresolvedSID = .\ADACLScan.ps1 -Base $nc -Scope subtree -Filter '(objectClass=*)' -Owner -FilterTrustee 'S-1-5*'
$unresolvedSID | ForEach-Object {
$unresolvedSIDArray.add($_)
}
}
Unresolved SIDs - all objects in the domain partition
⚠️ Execution time depends on number of objects⚠️
$unresolvedSIDArray = .\ADACLScan.ps1 -Base (Get-ADRootDSE).defaultNamingContext -Scope subtree -Filter '(objectClass=*)' -Owner -FilterTrustee 'S-1-5*'
Unresolved SIDs on OUs and containers only
⚠️ Execution time depends on number of objects⚠️
$unresolvedSIDArray= .\ADACLScan.ps1 -Base (Get-ADRootDSE).defaultNamingContext -Scope subtree -Filter '(|(objectClass=organizationalUnit)(objectClass=container))' -Owner -FilterTrustee 'S-1-5*'
Unresolved SIDs on GPO only
⚠️ Execution time depends on number of objects⚠️
[System.Collections.Generic.List[PSObject]]$unresolvedSIDArray = @()
$unresolvedSID = .\ADACLScan.ps1 -GPO -Scope subtree -Owner -FilterTrustee 'S-1-5*'
$unresolvedSID | ForEach-Object {
$unresolvedSIDArray.add($_)
}
Unresolved SIDs on AD-integrated DNS partitions
$adIntegratedDNSNC = (Get-ADRootDSE).namingContexts | Where-Object {$_ -like 'DC=DomainDNSZones*' -or $_ -like 'DC=ForestDNSZones*'}
[System.Collections.Generic.List[PSObject]]$unresolvedSIDArray = @()
foreach($nc in $adIntegratedDNSNC){
$unresolvedSID = .\ADACLScan.ps1 -Base $nc -Scope subtree -Filter '(objectClass=*)' -Owner -FilterTrustee 'S-1-5*'
$unresolvedSID | ForEach-Object {
$unresolvedSIDArray.add($_)
}
}
Advanced use of results
If you wish to delete unknown SIDs or modify the owner, you can use the following commands.
Delete unknown SIDs
$DNWithUnresolvedSID = ($unresolvedSIDArray | Where-Object {$_.Access -ne 'Owner'}).Object
foreach ($dn in $DNWithUnresolvedSID){
$acl = Get-Acl "AD:\$dn"
$aclsToDelete = $acl.Access | Where-Object {$_.IdentityReference -like 'S-1-5*'}
foreach($aclToDelete in $aclsToDelete){
$acl.RemoveAccessRule($aclToDelete)
}
Set-Acl -Path "AD:\$dn" -AclObject $acl
}
Change owner
$DNWithUnresolvedSIDOwner = ($unresolvedSIDArray | Where-Object {$_.Access -eq 'Owner'}).Object
$newOwner = New-Object System.Security.Principal.Ntaccount("Domain Admins")
foreach ($dn in $DNWithUnresolvedSIDOwner){
$acl = Get-Acl "AD:\$dn"
$acl.SetOwner($newOwner)
Set-Acl -Path "AD:\$dn" -AclObject $acl
}
Clap
Comments