Last active
October 25, 2021 00:00
-
-
Save kewalaka/3e111a6d1747fe3f90991e4ad5bb8da6 to your computer and use it in GitHub Desktop.
This uses ADSI to find accounts that are using unconstrained delegation, use of ADSI is to allow this to run on machines that don't have the AD cmdlets installed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# assume we're just dealing with the current domain | |
$SearchRoot = "DC=" + (($env:USERDNSDOMAIN).split(".") -join ",DC=") | |
# assume we can get a domain controller IP by grabbing the DNS setting from the interface with the default route. | |
$DomainControllerIP = (Get-DnsClientServerAddress -InterfaceIndex (Get-netroute -DestinationPrefix '0.0.0.0/0').ifIndex -AddressFamily IPv4).ServerAddresses | Select-Object -First 1 | |
$DomainDN = "LDAP://$($DomainControllerIP):$($Port)/$SearchRoot" | |
# computers | |
$ldapFilter = '(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))' | |
[System.Collections.ArrayList]$Properties = @('distinguishedname', 'samAccountName', 'objectClass', 'userAccountControl') | |
# users | |
$ldapFilter = '(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=524288))' | |
[System.Collections.ArrayList]$Properties = @('distinguishedname', 'UserPrincipalName', 'userAccountControl', 'createtimestamp', 'modifytimestamp') | |
# both - be careful to select properties that are relevant to all objectClasses, this isn't validated. | |
$ldapFilter = '(userAccountControl:1.2.840.113556.1.4.803:=524288)' | |
[System.Collections.ArrayList]$Properties = @('distinguishedname', 'samAccountName', 'userAccountControl', 'createtimestamp', 'modifytimestamp') | |
$Searcher = New-Object -TypeName System.DirectoryServices.DirectorySearcher | |
$Searcher.Filter = $LDAPFilter | |
if ($Properties -ne "*") { | |
[void]$searcher.PropertiesToLoad.AddRange($Properties) | |
} | |
$searcher.PageSize = 1000 # stop result truncation | |
$Domain = New-Object -TypeName System.DirectoryServices.DirectoryEntry -ArgumentList $DomainDN | |
$Searcher.SearchRoot = $Domain | |
# cast to an array otherwise the use case there is one result has be treated differently | |
[array]$Results = ($Searcher.FindAll()).Properties | |
if ($results.Length -eq 0) { | |
Write-Host 'No results found from initial LDAP filter.' | |
} | |
else { | |
# convert the array to a PS object | |
$output = @() | |
# use a hashtable to record the properties of each result dynamically | |
$tempHashtable = @{} | |
for ($i = 0; $i -lt ($Results | Measure-Object).count; $i++) { | |
$results[$i].PropertyNames | ForEach-Object { | |
# cast to a string otherwise get type of System.DirectoryServices.ResultPropertyValueCollection | |
# join arrays using commas | |
$tempHashtable[$_] = [string](($results[$i].$_ -join ",")) | |
} | |
$output += [PSCustomObject]$tempHashtable | Select-Object $properties | |
} | |
# we're only interested in useraccountcontrol to check for disabled accounts | |
$properties.remove('userAccountControl') | |
# display results, ignore DCs, since these required unconstrained delegation to function. | |
$finalResult = $output | Where-Object ({ $_.distinguishedName -notmatch 'OU=Domain Controllers' -and | |
# also ignore disabled accounts | |
(($_.userAccountControl -band 2) -ne 2) }) | Select-Object $properties | |
if ($finalResult.Count -eq 0) { | |
Write-Host 'No results found.' | |
} | |
else { | |
$finalResult | Format-Table -AutoSize | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment