Skip to content

Instantly share code, notes, and snippets.

@kewalaka
Last active October 25, 2021 00:00
Show Gist options
  • Save kewalaka/3e111a6d1747fe3f90991e4ad5bb8da6 to your computer and use it in GitHub Desktop.
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.
# 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