ad-enumeration-native.md (26044B)
1 --- 2 title: "Active Directory Enumeration — Native Tooling" 3 description: "Native Get-AD* and LDAP enumeration: fine-tuning -Filter/-LDAPFilter, finding deleted accounts in the AD Recycle Bin, ADSI when RSAT is missing — without reaching for PowerView." 4 category: active-directory 5 subcategory: "Tooling & Recon" 6 tags: [active-directory, enumeration, powershell, ldap, recycle-bin, deleted-objects, laps, gmsa, dcsync, delegation, trusts, kerberoasting, opsec] 7 tools: ["ActiveDirectory module (Get-AD*)", "ldapsearch", "ADSI / adsisearcher", "dsquery", "setspn", "nltest", "netexec/nxc", "Get-Acl (AD PSDrive)"] 8 difficulty: intermediate 9 updated: "2026-09-25" 10 source: "vault:06PdfCheatSheets/Active Directory/AD-Enumeration-Native" 11 --- 12 13 # Active Directory Enumeration — Native Tooling 14 15 The Microsoft-signed **`ActiveDirectory`** module (and, when it is missing, raw **ADSI / LDAP**) answers almost every enumeration question on a domain-joined box — who, what, where, which rights, which stale or **deleted** object — with no dropped tooling. PowerView is powerful, but for read-only recon it is an extra artefact you rarely need. This card is about driving `-Filter` and `-LDAPFilter` **precisely**, so you stop pulling the whole directory and grepping, and pull exactly the objects you want. 16 17 > [!tip] When you do NOT need PowerView 18 > If the task is "find objects / read attributes / list membership / find stale or deleted objects", the native `Get-AD*` cmdlets do it, are already present on any host with RSAT (always on a DC), are signed, and are quieter. Reach for PowerView only for what it genuinely adds: quick object-ACL enumeration (`Get-DomainObjectAcl`), GPO-to-OU mapping, and one-liner delegation/trust hunts — and even those have native equivalents (see the last table). 19 20 ## Setup — get the module loaded 21 22 ```powershell 23 Get-Module -ListAvailable ActiveDirectory # present? 24 Import-Module ActiveDirectory # load it 25 Get-ADDomain # sanity check: you can reach a DC 26 (Get-ADDomain).DomainSID # domain SID (handy for RID math) 27 ``` 28 29 No RSAT on the box? Install the capability (admin), or skip to the ADSI section: 30 31 ```powershell 32 # Windows 10/11 client: 33 Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 34 # Windows Server: 35 Install-WindowsFeature -Name RSAT-AD-PowerShell 36 ``` 37 38 > [!info] Target a specific DC / creds 39 > Every `Get-AD*` cmdlet takes `-Server <dc.fqdn>` and `-Credential (Get-Credential)`. From a non-domain host (with `runas /netonly`), that is how you query without being joined. 40 41 ## The core cmdlets 42 43 | Cmdlet | Answers | 44 |---|---| 45 | `Get-ADUser` | users + attributes (SPNs, UAC flags, lastLogon, description) | 46 | `Get-ADGroup` / `Get-ADGroupMember` | groups; who is IN a group (`-Recursive` for nested) | 47 | `Get-ADComputer` | computers; OS, delegation, lastLogon | 48 | `Get-ADObject` | **any** object by LDAP filter — the universal tool (incl. deleted) | 49 | `Get-ADDomain` / `Get-ADForest` | functional level, naming contexts, FSMO | 50 | `Get-ADTrust` | trust relationships (direction, transitivity) | 51 | `Get-ADServiceAccount` | (g)MSAs and who may retrieve the password | 52 | `Get-ADOrganizationalUnit` | OU tree (targets for `-SearchBase`) | 53 54 ```powershell 55 Get-ADUser -Identity alfred -Properties * # everything on one user 56 Get-ADGroupMember "Domain Admins" -Recursive | ft name,objectClass 57 Get-ADComputer -Filter * -Properties OperatingSystem | ft name,OperatingSystem 58 Get-ADObject -Filter "name -eq 'alfred'" -Properties * # any object, any class 59 ``` 60 61 ## Fine-tuning with `-Filter` (PowerShell syntax) 62 63 `-Filter` takes a PowerShell-ish expression the module translates to LDAP. Quote the whole filter; single-quote literal values; compare booleans to `$true`/`$false`; `*` is the wildcard with `-like`. 64 65 Operators: `-eq -ne -lt -gt -le -ge -like -notlike -and -or -not -bor -band` 66 67 ```powershell 68 Get-ADUser -Filter "Enabled -eq '$true'" # enabled users 69 Get-ADUser -Filter "Description -like '*pass*'" # creds in descriptions 70 Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName # kerberoastable 71 Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} # AS-REP roastable 72 Get-ADUser -Filter "PasswordNeverExpires -eq '$true' -and Enabled -eq '$true'" 73 Get-ADUser -Filter "adminCount -eq 1" # protected / privileged (AdminSDHolder) 74 Get-ADComputer -Filter {TrustedForDelegation -eq $true} # unconstrained delegation 75 Get-ADUser -Filter "LastLogonDate -lt '$((Get-Date).AddDays(-90))'" # stale accounts 76 ``` 77 78 > [!warning] Filter gotchas 79 > - Default properties are few — if you **filter or display** an attribute that isn't returned by default (SPN, `lastLogon`, `userAccountControl`), add it with `-Properties`. 80 > - Braces `{ }` let you use `$true` bare; the string form needs `'$true'`. Both work — be consistent. 81 > - `-Filter *` means "everything" — fine for computers, heavy for a big user base. Prefer a real predicate. 82 83 ## Fine-tuning with `-LDAPFilter` (raw LDAP) 84 85 When the PowerShell filter fights you — bitwise UAC flags, negation, exact attribute names — drop to raw LDAP. Operators sit at the front: `(&(a)(b))` = AND, `(|(a)(b))` = OR, `(!(a))` = NOT, `*` = wildcard/presence. 86 87 ```powershell 88 Get-ADObject -LDAPFilter "(servicePrincipalName=*)" -Properties servicePrincipalName # SPNs 89 Get-ADObject -LDAPFilter "(&(objectClass=user)(objectCategory=person))" 90 Get-ADObject -LDAPFilter "(&(objectClass=group)(!(member=*)))" # empty groups 91 Get-ADUser -LDAPFilter "(memberOf=CN=Domain Admins,CN=Users,DC=htb,DC=local)" 92 ``` 93 94 `userAccountControl` bits use the bitwise matching rule OID `1.2.840.113556.1.4.803`: 95 96 ```powershell 97 # disabled accounts (bit 0x2) 98 Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=2)" 99 # password never expires (0x10000 = 65536) 100 Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=65536)" 101 # don't require pre-auth (0x400000 = 4194304) -> AS-REP roast 102 Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=4194304)" 103 # trusted for delegation (0x80000 = 524288) -> unconstrained 104 Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)" 105 ``` 106 107 | UAC bit | Value | Meaning | 108 |---|---|---| 109 | 0x0002 | 2 | Account disabled | 110 | 0x0020 | 32 | Password not required | 111 | 0x0200 | 512 | Normal account | 112 | 0x10000 | 65536 | Password never expires | 113 | 0x80000 | 524288 | Trusted for delegation (unconstrained) | 114 | 0x100000 | 1048576 | Not delegated (sensitive) | 115 | 0x400000 | 4194304 | Does not require Kerberos pre-auth | 116 | 0x0010 | 16 | Account locked out (transient) | 117 | 0x0040 | 64 | Password can't change | 118 | 0x0080 | 128 | Reversible (cleartext) password storage allowed | 119 | 0x2000 | 8192 | Server trust account (domain controller) | 120 | 0x40000 | 262144 | Smart-card required for interactive logon | 121 | 0x200000 | 2097152 | Use DES keys only (weak Kerberos / downgrade) | 122 | 0x800000 | 8388608 | Password expired | 123 | 0x1000000 | 16777216 | Trusted to auth for delegation (constrained + protocol transition / S4U2Self) | 124 | 0x4000000 | 67108864 | Partial secrets account (RODC) | 125 126 > [!tip] AND-rule vs OR-rule for UAC bits 127 > `…1.2.840.113556.1.4.803:=X` (BIT_AND) matches when `(uac & X) == X` — **every** bit in `X` must be set, so require two flags either by summing them (`32 + 65536 = 65568`) or by AND-ing two clauses. `…1.2.840.113556.1.4.804:=X` (BIT_OR) matches when `(uac & X) != 0` — **any** of the bits. Use `803` for "has all of", `804` for "has any of". 128 129 ## High-value `-LDAPFilter` recipes 130 131 Targeted one-liners for the objects worth finding first. Each filters on exactly the attribute it needs — add `-Properties` to *display* it. 132 133 ```powershell 134 # Cleartext creds parked in description / info (Notes) fields 135 Get-ADUser -LDAPFilter "(|(description=*pass*)(description=*pwd*)(info=*pass*)(info=*pwd*))" ` 136 -Properties description,info | ft SamAccountName,description,info 137 138 # Privileged AND kerberoastable — an SPN on an adminCount=1 principal 139 Get-ADUser -LDAPFilter "(&(servicePrincipalName=*)(adminCount=1))" ` 140 -Properties servicePrincipalName,adminCount,memberOf | ft SamAccountName,servicePrincipalName 141 142 # PASSWD_NOTREQD (blank password may be allowed) — bit 0x20 = 32 143 Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=32)" -Properties userAccountControl 144 145 # PASSWD_NOTREQD *and* DONT_EXPIRE_PASSWORD (32 + 65536 = 65568) — two equivalent forms 146 Get-ADUser -LDAPFilter "(&(userAccountControl:1.2.840.113556.1.4.803:=32)(userAccountControl:1.2.840.113556.1.4.803:=65536))" 147 Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=65568)" 148 149 # Reversible encryption enabled (0x80 = 128) — password recoverable from NTDS 150 Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=128)" 151 152 # Constrained delegation w/ protocol transition (0x1000000 = 16777216) — S4U abuse targets 153 Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=16777216)" -Properties msDS-AllowedToDelegateTo 154 155 # Domain controllers by UAC (SERVER_TRUST_ACCOUNT 0x2000 = 8192) 156 Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=8192)" -Properties dNSHostName 157 158 # Computers by OS — patch-level / EOL targeting (operatingSystem + build number) 159 Get-ADComputer -LDAPFilter "(operatingSystem=*Server*2012*)" -Properties operatingSystem,operatingSystemVersion | 160 ft Name,operatingSystem,operatingSystemVersion 161 Get-ADComputer -LDAPFilter "(|(operatingSystem=*2008*)(operatingSystem=*2003*))" -Properties operatingSystem 162 ``` 163 164 | Want | `-LDAPFilter` | 165 |---|---| 166 | Creds in description/info | `(\|(description=*pass*)(info=*pass*))` | 167 | SPN + adminCount=1 | `(&(servicePrincipalName=*)(adminCount=1))` | 168 | Password not required | `(userAccountControl:1.2.840.113556.1.4.803:=32)` | 169 | Not-required + never-expires | `(userAccountControl:1.2.840.113556.1.4.803:=65568)` | 170 | Reversible encryption | `(userAccountControl:1.2.840.113556.1.4.803:=128)` | 171 | Protocol-transition delegation | `(userAccountControl:1.2.840.113556.1.4.803:=16777216)` | 172 | Domain controllers | `(userAccountControl:1.2.840.113556.1.4.803:=8192)` | 173 | OS = Server 2012 | `(operatingSystem=*Server*2012*)` | 174 175 ## Scope and attributes — pull only what you need 176 177 ```powershell 178 # only the columns you want, not the whole object 179 Get-ADUser -Filter * -Properties SamAccountName,Description,LastLogonDate | 180 Select SamAccountName,Description,LastLogonDate 181 182 # restrict the search to one OU (and its children) 183 Get-ADUser -SearchBase "OU=Servers,DC=htb,DC=local" -Filter * 184 185 # scope: Base (this object) / OneLevel (direct children) / Subtree (default) 186 Get-ADObject -SearchBase "DC=htb,DC=local" -SearchScope OneLevel -LDAPFilter "(objectClass=organizationalUnit)" 187 ``` 188 189 > [!info] Read it back with the right tool 190 > `Select`, `Format-Table (ft)`, `Format-List (fl)` and `Sort-Object` shape output; `Export-Csv` banks it for the report. Pull `-Properties *` once on an interesting object to learn its real attribute names, then filter precisely. 191 192 ## Deleted / tombstoned objects & the AD Recycle Bin 193 194 This is the case people reach for PowerView on and shouldn't — **deleted objects are native `Get-ADObject` territory**. When something is removed, its tombstone lingers, and if the AD Recycle Bin is enabled it can be **restored with attributes intact**. 195 196 List every deleted object with its old parent and SID: 197 198 ```powershell 199 Get-ADObject -Filter 'isDeleted -eq $true -and name -ne "Deleted Objects"' ` 200 -IncludeDeletedObjects -Properties objectSid,lastKnownParent,whenChanged,msDS-LastKnownRDN | 201 ft name,objectSid,lastKnownParent 202 ``` 203 204 Inspect one deleted object fully, then restore it (Recycle Bin must be enabled): 205 206 ```powershell 207 Get-ADObject -LDAPFilter "(msDS-LastKnownRDN=alfred)" -IncludeDeletedObjects -Properties * 208 Restore-ADObject -Identity "<distinguishedName-with-\0ADEL:GUID>" 209 210 # is the Recycle Bin feature on? 211 Get-ADOptionalFeature -Filter "name -like 'Recycle Bin Feature'" | ft name,EnabledScopes 212 ``` 213 214 > [!note] Why this matters on a box 215 > A deleted object can hold a still-valid SID/attributes, a group it belonged to, or a service account that was "removed" but restorable — reading its attributes (or restoring it) can hand you an identity or a path the live tree hides. That is exactly the fine-tuned, native query PowerView is not needed for. 216 217 ## Service accounts, gMSA & delegation 218 219 ```powershell 220 Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword 221 # who can read a gMSA password -> if it's you/your group, you can pull it 222 Get-ADServiceAccount -Identity gmsaSvc -Properties * | 223 Select Name,PrincipalsAllowedToRetrieveManagedPassword 224 225 # constrained delegation targets 226 Get-ADObject -LDAPFilter "(msDS-AllowedToDelegateTo=*)" -Properties msDS-AllowedToDelegateTo 227 # resource-based constrained delegation (who can act on this computer) 228 Get-ADComputer -Filter * -Properties PrincipalsAllowedToDelegateToAccount | 229 Where-Object {$_.PrincipalsAllowedToDelegateToAccount} 230 ``` 231 232 ## LAPS & gMSA — who can read the secret 233 234 LAPS and gMSA passwords are AD attributes; the win is finding the objects **and** confirming *you* can read them. The confidential attributes (`ms-Mcs-AdmPwd`, `msLAPS-Password`, `msDS-ManagedPassword`) are only returned to principals with the read right, so a presence filter on them doubles as an access check. 235 236 ### LAPS readers 237 238 ```powershell 239 # LAPS-managed computers (the expiry attr is world-readable) — v1 and v2 240 Get-ADComputer -LDAPFilter "(ms-Mcs-AdmPwdExpirationTime=*)" -Properties ms-Mcs-AdmPwdExpirationTime # LAPS v1 241 Get-ADComputer -LDAPFilter "(msLAPS-PasswordExpirationTime=*)" -Properties msLAPS-PasswordExpirationTime # LAPS v2 242 243 # Computers whose ms-Mcs-AdmPwd you can actually READ (confidential attr only returns to authorised readers) 244 Get-ADComputer -LDAPFilter "(ms-Mcs-AdmPwd=*)" -Properties ms-Mcs-AdmPwd | ft Name,ms-Mcs-AdmPwd 245 246 # Who is delegated LAPS read on an OU 247 Find-AdmPwdExtendedRights -Identity "OU=Servers,DC=htb,DC=local" # LAPS v1 (AdmPwd.PS module) 248 Find-LapsADExtendedRights -Identity "OU=Servers,DC=htb,DC=local" # LAPS v2 (Windows LAPS module) 249 ``` 250 251 ### gMSA readers 252 253 ```powershell 254 # All gMSAs by class, with the password-refresh interval 255 Get-ADObject -LDAPFilter "(objectClass=msDS-GroupManagedServiceAccount)" ` 256 -Properties sAMAccountName,msDS-ManagedPasswordInterval | ft sAMAccountName,msDS-ManagedPasswordInterval 257 258 # Who may retrieve each gMSA password (msDS-GroupMSAMembership, surfaced friendly) 259 Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword | 260 Select Name,PrincipalsAllowedToRetrieveManagedPassword 261 ``` 262 263 ```bash 264 # From Linux — same objects 265 ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \ 266 "(objectClass=msDS-GroupManagedServiceAccount)" sAMAccountName msDS-GroupMSAMembership 267 ``` 268 269 > [!info] Extract, don't just find 270 > Enumeration stops at *who can read it*. To pull the actual secret see [Attack #72 — LAPS Password Extraction](/sheets/active-directory/attack-72-laps-password-extraction) and [Attack #73 — gMSA Password Extraction](/sheets/active-directory/attack-73-gmsa-password-extraction). 271 272 ## DCSync rights — read the domain-head ACL 273 274 DCSync needs two extended rights on the **domain object** itself: `DS-Replication-Get-Changes` (`1131f6aa-…`) and `DS-Replication-Get-Changes-All` (`1131f6ad-…`). Read the domain head's ACL and list every principal that holds them — anyone beyond DCs / Domain Admins / Enterprise Admins is a finding. 275 276 ```powershell 277 $dcsync = '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2','1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' 278 $dn = (Get-ADDomain).DistinguishedName 279 (Get-Acl "AD:\$dn").Access | 280 Where-Object { $dcsync -contains $_.ObjectType.ToString() } | 281 Select-Object IdentityReference,ActiveDirectoryRights,ObjectType,AccessControlType 282 ``` 283 284 An entry with `ObjectType = 00000000-0000-0000-0000-000000000000` and `ActiveDirectoryRights` including `GenericAll` / `WriteDacl` / `ExtendedRight` grants DCSync implicitly (all extended rights). A third right, `DS-Replication-Get-Changes-In-Filtered-Set` (`89e95b76-444d-4c62-991a-0facbeda640c`), covers RODC-filtered attributes. 285 286 > [!info] Turn the finding into the attack 287 > A non-default principal holding both replication rights can replicate secrets. Execute it from [Attack #37 — DCSync](/sheets/active-directory/attack-37-dcsync-attack) — `impacket-secretsdump -just-dc <domain>/<user>@<dc>` or `nxc smb <dc> -u u -p p --ntds`. 288 289 ## Trusts — direction & SID filtering 290 291 `Get-ADTrust` resolves the trust's direction and type and — critical for cross-domain escalation — whether **SID filtering** is enforced. 292 293 ```powershell 294 Get-ADTrust -Filter * -Properties * | 295 Select Name,Direction,TrustType,IntraForest,ForestTransitive,SIDFilteringQuarantined,SIDFilteringForestAware,SelectiveAuthentication,TrustAttributes | fl 296 ``` 297 298 | Property | Reading it | 299 |---|---| 300 | `Direction` | `Inbound` (they trust us), `Outbound` (we trust them), `BiDirectional` | 301 | `IntraForest` | `True` = parent/child inside one forest (SID filtering off by default → SID-history viable) | 302 | `ForestTransitive` | `True` = trust to a separate forest | 303 | `SIDFilteringQuarantined` | `True` = SID filtering ON, injected SID-history dropped; `False` = injection viable | 304 | `SIDFilteringForestAware` | forest-boundary SID-filtering state (nuanced — read alongside `TrustAttributes`) | 305 | `SelectiveAuthentication` | `True` = principals need an explicit *Allowed-to-authenticate* per resource | 306 307 Raw and module-free — the `trustedDomain` object carries the numeric bitmask: 308 309 ```powershell 310 Get-ADObject -LDAPFilter "(objectClass=trustedDomain)" ` 311 -Properties trustPartner,trustDirection,trustType,trustAttributes,securityIdentifier 312 ``` 313 314 ```bash 315 nltest /domain_trusts /all_trusts /v # direction + type from any domain-joined host 316 ``` 317 318 `trustDirection`: `1` inbound, `2` outbound, `3` bidirectional. `trustAttributes` bits: `0x1` non-transitive, `0x4` quarantined (SID filtering **on**), `0x8` forest-transitive, `0x20` within-forest, `0x40` treat-as-external. 319 320 > [!info] Where an unfiltered trust goes 321 > Intra-forest (parent/child) trusts don't SID-filter by default, so a child-domain compromise reaches the forest root via SID-history. See [Attack #68 — Cross-Domain Trust Abuse (SID History)](/sheets/active-directory/attack-68-cross-domain-trust-abuse-sid-history) and [Attack #69 — Forest Trust Abuse](/sheets/active-directory/attack-69-forest-trust-abuse-cross-forest-ticket-forging). 322 323 ## No RSAT? ADSI / LDAP without the module 324 325 `[adsisearcher]` and `System.DirectoryServices` ship on stock Windows — no module, no dropped binary. 326 327 ```powershell 328 ([adsisearcher]"(servicePrincipalName=*)").FindAll() # SPNs 329 $s = [adsisearcher]"(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" 330 $s.PropertiesToLoad.AddRange(@("samaccountname")); $s.FindAll().Properties.samaccountname 331 ``` 332 333 Built-in binaries when PowerShell is awkward: 334 335 ```bash 336 dsquery user -limit 0 # all users (if dsquery present) 337 net user /domain ; net group "Domain Admins" /domain # quick membership 338 nltest /dclist:htb.local ; nltest /domain_trusts # DCs and trusts 339 setspn -T htb.local -Q */* # SPNs (kerberoast targets) 340 ``` 341 342 ## From Linux — same filters, different client 343 344 `ldapsearch` speaks the exact same LDAP filters as `-LDAPFilter`: 345 346 ```bash 347 ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \ 348 '(servicePrincipalName=*)' sAMAccountName servicePrincipalName 349 # AS-REP roastable 350 ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \ 351 '(userAccountControl:1.2.840.113556.1.4.803:=4194304)' sAMAccountName 352 # deleted objects need the Show Deleted Objects control: 353 ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \ 354 -E '!1.2.840.113556.1.4.417' '(isDeleted=TRUE)' msDS-LastKnownRDN lastKnownParent 355 ``` 356 357 > [!info] Collectors 358 > `nxc ldap $DC -u u -p p --query "<ldapfilter>" "<attrs>"` runs the same filters at scale; BloodHound / RustHound-CE ingest the whole graph when you want relationships rather than a targeted lookup. 359 360 ## Quiet queries — LDAP volume & signing (OPSEC) 361 362 Native LDAP recon is low-signal, not no-signal. Keep it that way. 363 364 - **Don't pull the directory.** `-Filter *` / `(objectClass=*)` over a `Subtree` scope walks every object and every default attribute — big, slow, loud. Scope with `-SearchBase`, predicate with a real filter, and list only the attributes you need. Reserve `-Properties *` for a single already-identified object. 365 - **Watch paging.** DCs cap responses at the `MaxPageSize` policy (default **1000**). `Get-AD*` pages automatically; cap the pull with `-ResultSetSize` and tune the page with `-ResultPageSize`. `ldapsearch` needs `-E pr=1000/noprompt`; without it a large search trips the size limit at 1000. 366 - **Bind securely / expect signing.** Hardened DCs enforce **LDAP signing** and **channel binding** and refuse simple binds. `Get-AD*` and `[adsisearcher]` negotiate sign-and-seal already. `ldapsearch` simple bind on `389` sends the password in cleartext — use `-Z` (StartTLS) or `ldaps://…:636`. `nxc ldap` supports `-k` and LDAPS for the same reason. 367 - **Prefer one DC you already talk to.** Spraying queries across every DC multiplies the trail; pin `-Server <dc>` to the one you hold a session with. 368 369 ```powershell 370 Get-ADUser -LDAPFilter "(servicePrincipalName=*)" -ResultPageSize 200 -ResultSetSize 500 ` 371 -SearchBase "OU=Servers,DC=htb,DC=local" -Properties servicePrincipalName -Server dc01.htb.local 372 ``` 373 374 > [!warning] What lights up 375 > - **4662** (object access) fires when a **SACL** audits an attribute — reading confidential `ms-Mcs-AdmPwd` / `msDS-ManagedPassword` is the classic trigger. 376 > - **1644** logs expensive/inefficient LDAP searches — only when *15 Field Engineering* diagnostics are raised, but a `(objectClass=*)` subtree dump is exactly what it flags. 377 > - **2889** logs clients doing unsigned/cleartext simple binds when LDAP-interface-events diagnostics are on — your `ldapsearch -x` on `389` shows up here. 378 379 ## Native vs PowerView — quick map 380 381 | Task | Native | PowerView | 382 |---|---|---| 383 | Find users/computers | `Get-ADUser` / `Get-ADComputer` `-Filter`/`-LDAPFilter` | `Get-DomainUser` / `Get-DomainComputer` | 384 | Group membership | `Get-ADGroupMember -Recursive` | `Get-DomainGroupMember -Recurse` | 385 | SPNs (kerberoast) | `(servicePrincipalName=*)` | `Get-DomainUser -SPN` | 386 | AS-REP roastable | UAC bit `4194304` filter | `Get-DomainUser -PreauthNotRequired` | 387 | Deleted objects | `Get-ADObject -IncludeDeletedObjects` | *(n/a — use native)* | 388 | Trusts | `Get-ADTrust -Filter *` | `Get-DomainTrust` | 389 | Delegation | `msDS-AllowedToDelegateTo` / `TrustedForDelegation` | `Get-DomainComputer -Unconstrained` | 390 | Object ACLs | `Get-Acl "AD:\<DN>"` | `Get-DomainObjectAcl` *(easier)* | 391 | GPO to OU mapping | `Get-GPO` / `Get-GPInheritance` (GroupPolicy module) | `Get-DomainGPO` / `Get-DomainOU` | 392 | LAPS read | `(ms-Mcs-AdmPwd=*)` / `Get-LapsADPassword` | `Get-DomainComputer -Properties ms-Mcs-AdmPwd` | 393 | gMSA read | `Get-ADServiceAccount -Properties PrincipalsAllowedToRetrieveManagedPassword` | `Get-DomainObject -LDAPFilter "(objectClass=msDS-GroupManagedServiceAccount)"` | 394 | DCSync rights | `Get-Acl "AD:\<domainDN>"` (replication GUIDs) | `Get-DomainObjectAcl -SearchBase <domainDN> -ResolveGUIDs` | 395 | Password not required | UAC bit `32` filter | `Get-DomainUser -UACFilter PASSWD_NOTREQD` | 396 | Computers by OS | `(operatingSystem=*2012*)` | `Get-DomainComputer -OperatingSystem "*2012*"` | 397 398 > [!tip] The habit to build 399 > Ask "what object and which attribute do I actually want?", write the `-LDAPFilter` for it, add `-Properties` for the attributes, and `-SearchBase` to scope it. That single targeted query — native, signed, already present — is almost always the answer, **deleted objects included**. 400 401 402 ## Troubleshooting 403 404 | Problem | Cause & fix | 405 |---------|-------------| 406 | `Get-ADUser : term not recognized` | The ActiveDirectory module is not loaded / RSAT absent. Import it, or drop to the ADSI / `System.DirectoryServices` path below — no install needed | 407 | Cmdlets work but return nothing | You are likely bound to a read-only GC or the wrong `-SearchBase`. Confirm the domain DN with `Get-ADDomain` and widen the base | 408 | `-LDAPFilter` returns fewer objects than expected | The default page size caps results. The AD cmdlets page automatically; raw ADSI/`DirectorySearcher` does not — set `.PageSize = 1000` | 409 | `A referral was returned from the server` | The query crossed a domain/OU boundary the current server cannot answer. Target a DC for that domain with `-Server`, or query the GC (`:3268`) for a forest-wide read | 410 | Attribute you asked for is blank | It is not in the default property set. Add it explicitly: `-Properties memberof,servicePrincipalName,lastLogonTimestamp` | 411 | `lastLogonTimestamp` looks wrong | It is replicated only every ~14 days by design. For precise timing you need per-DC `lastLogon`, which does not replicate | 412 | ADSI works locally but fails from a foothold shell | No Kerberos/NTLM context. Pass explicit creds to the `DirectoryEntry`, or run under `runas /netonly` | 413 414 ## See Also 415 416 - **[PowerView & PowerUp](/sheets/active-directory/powerview-powerup)** — the offensive toolkit whose queries this sheet maps to native equivalents of. 417 - **[BloodHound](/sheets/active-directory/bloodhound)** — graph the relationships once you have collected the objects. 418 - **[AD Recycle Bin Enumeration](/sheets/active-directory/ad-recycle-bin-enumeration)** — the deleted-object corner of the same directory. 419 - **[Kerberoasting](/sheets/active-directory/kerberoasting-local-on-host)** — act on the SPN-bearing accounts these filters surface. 420