Active Directory Enumeration — Native Tooling
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.
[!tip] When you do NOT need PowerView 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).
Setup — get the module loaded
Get-Module -ListAvailable ActiveDirectory # present?
Import-Module ActiveDirectory # load it
Get-ADDomain # sanity check: you can reach a DC
(Get-ADDomain).DomainSID # domain SID (handy for RID math)
No RSAT on the box? Install the capability (admin), or skip to the ADSI section:
# Windows 10/11 client:
Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
# Windows Server:
Install-WindowsFeature -Name RSAT-AD-PowerShell
[!info] Target a specific DC / creds Every
Get-AD*cmdlet takes-Server <dc.fqdn>and-Credential (Get-Credential). From a non-domain host (withrunas /netonly), that is how you query without being joined.
The core cmdlets
| Cmdlet | Answers |
|---|---|
Get-ADUser | users + attributes (SPNs, UAC flags, lastLogon, description) |
Get-ADGroup / Get-ADGroupMember | groups; who is IN a group (-Recursive for nested) |
Get-ADComputer | computers; OS, delegation, lastLogon |
Get-ADObject | any object by LDAP filter — the universal tool (incl. deleted) |
Get-ADDomain / Get-ADForest | functional level, naming contexts, FSMO |
Get-ADTrust | trust relationships (direction, transitivity) |
Get-ADServiceAccount | (g)MSAs and who may retrieve the password |
Get-ADOrganizationalUnit | OU tree (targets for -SearchBase) |
Get-ADUser -Identity alfred -Properties * # everything on one user
Get-ADGroupMember "Domain Admins" -Recursive | ft name,objectClass
Get-ADComputer -Filter * -Properties OperatingSystem | ft name,OperatingSystem
Get-ADObject -Filter "name -eq 'alfred'" -Properties * # any object, any class
Fine-tuning with -Filter (PowerShell syntax)
-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.
Operators: -eq -ne -lt -gt -le -ge -like -notlike -and -or -not -bor -band
Get-ADUser -Filter "Enabled -eq '$true'" # enabled users
Get-ADUser -Filter "Description -like '*pass*'" # creds in descriptions
Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName # kerberoastable
Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} # AS-REP roastable
Get-ADUser -Filter "PasswordNeverExpires -eq '$true' -and Enabled -eq '$true'"
Get-ADUser -Filter "adminCount -eq 1" # protected / privileged (AdminSDHolder)
Get-ADComputer -Filter {TrustedForDelegation -eq $true} # unconstrained delegation
Get-ADUser -Filter "LastLogonDate -lt '$((Get-Date).AddDays(-90))'" # stale accounts
[!warning] Filter gotchas
- Default properties are few — if you filter or display an attribute that isn’t returned by default (SPN,
lastLogon,userAccountControl), add it with-Properties.- Braces
{ }let you use$truebare; the string form needs'$true'. Both work — be consistent.-Filter *means “everything” — fine for computers, heavy for a big user base. Prefer a real predicate.
Fine-tuning with -LDAPFilter (raw LDAP)
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.
Get-ADObject -LDAPFilter "(servicePrincipalName=*)" -Properties servicePrincipalName # SPNs
Get-ADObject -LDAPFilter "(&(objectClass=user)(objectCategory=person))"
Get-ADObject -LDAPFilter "(&(objectClass=group)(!(member=*)))" # empty groups
Get-ADUser -LDAPFilter "(memberOf=CN=Domain Admins,CN=Users,DC=htb,DC=local)"
userAccountControl bits use the bitwise matching rule OID 1.2.840.113556.1.4.803:
# disabled accounts (bit 0x2)
Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=2)"
# password never expires (0x10000 = 65536)
Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=65536)"
# don't require pre-auth (0x400000 = 4194304) -> AS-REP roast
Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=4194304)"
# trusted for delegation (0x80000 = 524288) -> unconstrained
Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
| UAC bit | Value | Meaning |
|---|---|---|
| 0x0002 | 2 | Account disabled |
| 0x0020 | 32 | Password not required |
| 0x0200 | 512 | Normal account |
| 0x10000 | 65536 | Password never expires |
| 0x80000 | 524288 | Trusted for delegation (unconstrained) |
| 0x100000 | 1048576 | Not delegated (sensitive) |
| 0x400000 | 4194304 | Does not require Kerberos pre-auth |
| 0x0010 | 16 | Account locked out (transient) |
| 0x0040 | 64 | Password can’t change |
| 0x0080 | 128 | Reversible (cleartext) password storage allowed |
| 0x2000 | 8192 | Server trust account (domain controller) |
| 0x40000 | 262144 | Smart-card required for interactive logon |
| 0x200000 | 2097152 | Use DES keys only (weak Kerberos / downgrade) |
| 0x800000 | 8388608 | Password expired |
| 0x1000000 | 16777216 | Trusted to auth for delegation (constrained + protocol transition / S4U2Self) |
| 0x4000000 | 67108864 | Partial secrets account (RODC) |
[!tip] AND-rule vs OR-rule for UAC bits
…1.2.840.113556.1.4.803:=X(BIT_AND) matches when(uac & X) == X— every bit inXmust 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. Use803for “has all of”,804for “has any of”.
High-value -LDAPFilter recipes
Targeted one-liners for the objects worth finding first. Each filters on exactly the attribute it needs — add -Properties to display it.
# Cleartext creds parked in description / info (Notes) fields
Get-ADUser -LDAPFilter "(|(description=*pass*)(description=*pwd*)(info=*pass*)(info=*pwd*))" `
-Properties description,info | ft SamAccountName,description,info
# Privileged AND kerberoastable — an SPN on an adminCount=1 principal
Get-ADUser -LDAPFilter "(&(servicePrincipalName=*)(adminCount=1))" `
-Properties servicePrincipalName,adminCount,memberOf | ft SamAccountName,servicePrincipalName
# PASSWD_NOTREQD (blank password may be allowed) — bit 0x20 = 32
Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=32)" -Properties userAccountControl
# PASSWD_NOTREQD *and* DONT_EXPIRE_PASSWORD (32 + 65536 = 65568) — two equivalent forms
Get-ADUser -LDAPFilter "(&(userAccountControl:1.2.840.113556.1.4.803:=32)(userAccountControl:1.2.840.113556.1.4.803:=65536))"
Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=65568)"
# Reversible encryption enabled (0x80 = 128) — password recoverable from NTDS
Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=128)"
# Constrained delegation w/ protocol transition (0x1000000 = 16777216) — S4U abuse targets
Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=16777216)" -Properties msDS-AllowedToDelegateTo
# Domain controllers by UAC (SERVER_TRUST_ACCOUNT 0x2000 = 8192)
Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=8192)" -Properties dNSHostName
# Computers by OS — patch-level / EOL targeting (operatingSystem + build number)
Get-ADComputer -LDAPFilter "(operatingSystem=*Server*2012*)" -Properties operatingSystem,operatingSystemVersion |
ft Name,operatingSystem,operatingSystemVersion
Get-ADComputer -LDAPFilter "(|(operatingSystem=*2008*)(operatingSystem=*2003*))" -Properties operatingSystem
| Want | -LDAPFilter |
|---|---|
| Creds in description/info | (|(description=*pass*)(info=*pass*)) |
| SPN + adminCount=1 | (&(servicePrincipalName=*)(adminCount=1)) |
| Password not required | (userAccountControl:1.2.840.113556.1.4.803:=32) |
| Not-required + never-expires | (userAccountControl:1.2.840.113556.1.4.803:=65568) |
| Reversible encryption | (userAccountControl:1.2.840.113556.1.4.803:=128) |
| Protocol-transition delegation | (userAccountControl:1.2.840.113556.1.4.803:=16777216) |
| Domain controllers | (userAccountControl:1.2.840.113556.1.4.803:=8192) |
| OS = Server 2012 | (operatingSystem=*Server*2012*) |
Scope and attributes — pull only what you need
# only the columns you want, not the whole object
Get-ADUser -Filter * -Properties SamAccountName,Description,LastLogonDate |
Select SamAccountName,Description,LastLogonDate
# restrict the search to one OU (and its children)
Get-ADUser -SearchBase "OU=Servers,DC=htb,DC=local" -Filter *
# scope: Base (this object) / OneLevel (direct children) / Subtree (default)
Get-ADObject -SearchBase "DC=htb,DC=local" -SearchScope OneLevel -LDAPFilter "(objectClass=organizationalUnit)"
[!info] Read it back with the right tool
Select,Format-Table (ft),Format-List (fl)andSort-Objectshape output;Export-Csvbanks it for the report. Pull-Properties *once on an interesting object to learn its real attribute names, then filter precisely.
Deleted / tombstoned objects & the AD Recycle Bin
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.
List every deleted object with its old parent and SID:
Get-ADObject -Filter 'isDeleted -eq $true -and name -ne "Deleted Objects"' `
-IncludeDeletedObjects -Properties objectSid,lastKnownParent,whenChanged,msDS-LastKnownRDN |
ft name,objectSid,lastKnownParent
Inspect one deleted object fully, then restore it (Recycle Bin must be enabled):
Get-ADObject -LDAPFilter "(msDS-LastKnownRDN=alfred)" -IncludeDeletedObjects -Properties *
Restore-ADObject -Identity "<distinguishedName-with-\0ADEL:GUID>"
# is the Recycle Bin feature on?
Get-ADOptionalFeature -Filter "name -like 'Recycle Bin Feature'" | ft name,EnabledScopes
[!note] Why this matters on a box 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.
Service accounts, gMSA & delegation
Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword
# who can read a gMSA password -> if it's you/your group, you can pull it
Get-ADServiceAccount -Identity gmsaSvc -Properties * |
Select Name,PrincipalsAllowedToRetrieveManagedPassword
# constrained delegation targets
Get-ADObject -LDAPFilter "(msDS-AllowedToDelegateTo=*)" -Properties msDS-AllowedToDelegateTo
# resource-based constrained delegation (who can act on this computer)
Get-ADComputer -Filter * -Properties PrincipalsAllowedToDelegateToAccount |
Where-Object {$_.PrincipalsAllowedToDelegateToAccount}
LAPS & gMSA — who can read the secret
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.
LAPS readers
# LAPS-managed computers (the expiry attr is world-readable) — v1 and v2
Get-ADComputer -LDAPFilter "(ms-Mcs-AdmPwdExpirationTime=*)" -Properties ms-Mcs-AdmPwdExpirationTime # LAPS v1
Get-ADComputer -LDAPFilter "(msLAPS-PasswordExpirationTime=*)" -Properties msLAPS-PasswordExpirationTime # LAPS v2
# Computers whose ms-Mcs-AdmPwd you can actually READ (confidential attr only returns to authorised readers)
Get-ADComputer -LDAPFilter "(ms-Mcs-AdmPwd=*)" -Properties ms-Mcs-AdmPwd | ft Name,ms-Mcs-AdmPwd
# Who is delegated LAPS read on an OU
Find-AdmPwdExtendedRights -Identity "OU=Servers,DC=htb,DC=local" # LAPS v1 (AdmPwd.PS module)
Find-LapsADExtendedRights -Identity "OU=Servers,DC=htb,DC=local" # LAPS v2 (Windows LAPS module)
gMSA readers
# All gMSAs by class, with the password-refresh interval
Get-ADObject -LDAPFilter "(objectClass=msDS-GroupManagedServiceAccount)" `
-Properties sAMAccountName,msDS-ManagedPasswordInterval | ft sAMAccountName,msDS-ManagedPasswordInterval
# Who may retrieve each gMSA password (msDS-GroupMSAMembership, surfaced friendly)
Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword |
Select Name,PrincipalsAllowedToRetrieveManagedPassword
# From Linux — same objects
ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \
"(objectClass=msDS-GroupManagedServiceAccount)" sAMAccountName msDS-GroupMSAMembership
[!info] Extract, don’t just find Enumeration stops at who can read it. To pull the actual secret see Attack #72 — LAPS Password Extraction and Attack #73 — gMSA Password Extraction.
DCSync rights — read the domain-head ACL
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.
$dcsync = '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2','1131f6ad-9c07-11d1-f79f-00c04fc2dcd2'
$dn = (Get-ADDomain).DistinguishedName
(Get-Acl "AD:\$dn").Access |
Where-Object { $dcsync -contains $_.ObjectType.ToString() } |
Select-Object IdentityReference,ActiveDirectoryRights,ObjectType,AccessControlType
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.
[!info] Turn the finding into the attack A non-default principal holding both replication rights can replicate secrets. Execute it from Attack #37 — DCSync —
impacket-secretsdump -just-dc <domain>/<user>@<dc>ornxc smb <dc> -u u -p p --ntds.
Trusts — direction & SID filtering
Get-ADTrust resolves the trust’s direction and type and — critical for cross-domain escalation — whether SID filtering is enforced.
Get-ADTrust -Filter * -Properties * |
Select Name,Direction,TrustType,IntraForest,ForestTransitive,SIDFilteringQuarantined,SIDFilteringForestAware,SelectiveAuthentication,TrustAttributes | fl
| Property | Reading it |
|---|---|
Direction | Inbound (they trust us), Outbound (we trust them), BiDirectional |
IntraForest | True = parent/child inside one forest (SID filtering off by default → SID-history viable) |
ForestTransitive | True = trust to a separate forest |
SIDFilteringQuarantined | True = SID filtering ON, injected SID-history dropped; False = injection viable |
SIDFilteringForestAware | forest-boundary SID-filtering state (nuanced — read alongside TrustAttributes) |
SelectiveAuthentication | True = principals need an explicit Allowed-to-authenticate per resource |
Raw and module-free — the trustedDomain object carries the numeric bitmask:
Get-ADObject -LDAPFilter "(objectClass=trustedDomain)" `
-Properties trustPartner,trustDirection,trustType,trustAttributes,securityIdentifier
nltest /domain_trusts /all_trusts /v # direction + type from any domain-joined host
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.
[!info] Where an unfiltered trust goes 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) and Attack #69 — Forest Trust Abuse.
No RSAT? ADSI / LDAP without the module
[adsisearcher] and System.DirectoryServices ship on stock Windows — no module, no dropped binary.
([adsisearcher]"(servicePrincipalName=*)").FindAll() # SPNs
$s = [adsisearcher]"(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))"
$s.PropertiesToLoad.AddRange(@("samaccountname")); $s.FindAll().Properties.samaccountname
Built-in binaries when PowerShell is awkward:
dsquery user -limit 0 # all users (if dsquery present)
net user /domain ; net group "Domain Admins" /domain # quick membership
nltest /dclist:htb.local ; nltest /domain_trusts # DCs and trusts
setspn -T htb.local -Q */* # SPNs (kerberoast targets)
From Linux — same filters, different client
ldapsearch speaks the exact same LDAP filters as -LDAPFilter:
ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \
'(servicePrincipalName=*)' sAMAccountName servicePrincipalName
# AS-REP roastable
ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \
'(userAccountControl:1.2.840.113556.1.4.803:=4194304)' sAMAccountName
# deleted objects need the Show Deleted Objects control:
ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \
-E '!1.2.840.113556.1.4.417' '(isDeleted=TRUE)' msDS-LastKnownRDN lastKnownParent
[!info] Collectors
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.
Quiet queries — LDAP volume & signing (OPSEC)
Native LDAP recon is low-signal, not no-signal. Keep it that way.
- Don’t pull the directory.
-Filter */(objectClass=*)over aSubtreescope 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. - Watch paging. DCs cap responses at the
MaxPageSizepolicy (default 1000).Get-AD*pages automatically; cap the pull with-ResultSetSizeand tune the page with-ResultPageSize.ldapsearchneeds-E pr=1000/noprompt; without it a large search trips the size limit at 1000. - 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.ldapsearchsimple bind on389sends the password in cleartext — use-Z(StartTLS) orldaps://…:636.nxc ldapsupports-kand LDAPS for the same reason. - 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.
Get-ADUser -LDAPFilter "(servicePrincipalName=*)" -ResultPageSize 200 -ResultSetSize 500 `
-SearchBase "OU=Servers,DC=htb,DC=local" -Properties servicePrincipalName -Server dc01.htb.local
[!warning] What lights up
- 4662 (object access) fires when a SACL audits an attribute — reading confidential
ms-Mcs-AdmPwd/msDS-ManagedPasswordis the classic trigger.- 1644 logs expensive/inefficient LDAP searches — only when 15 Field Engineering diagnostics are raised, but a
(objectClass=*)subtree dump is exactly what it flags.- 2889 logs clients doing unsigned/cleartext simple binds when LDAP-interface-events diagnostics are on — your
ldapsearch -xon389shows up here.
Native vs PowerView — quick map
| Task | Native | PowerView |
|---|---|---|
| Find users/computers | Get-ADUser / Get-ADComputer -Filter/-LDAPFilter | Get-DomainUser / Get-DomainComputer |
| Group membership | Get-ADGroupMember -Recursive | Get-DomainGroupMember -Recurse |
| SPNs (kerberoast) | (servicePrincipalName=*) | Get-DomainUser -SPN |
| AS-REP roastable | UAC bit 4194304 filter | Get-DomainUser -PreauthNotRequired |
| Deleted objects | Get-ADObject -IncludeDeletedObjects | (n/a — use native) |
| Trusts | Get-ADTrust -Filter * | Get-DomainTrust |
| Delegation | msDS-AllowedToDelegateTo / TrustedForDelegation | Get-DomainComputer -Unconstrained |
| Object ACLs | Get-Acl "AD:\<DN>" | Get-DomainObjectAcl (easier) |
| GPO to OU mapping | Get-GPO / Get-GPInheritance (GroupPolicy module) | Get-DomainGPO / Get-DomainOU |
| LAPS read | (ms-Mcs-AdmPwd=*) / Get-LapsADPassword | Get-DomainComputer -Properties ms-Mcs-AdmPwd |
| gMSA read | Get-ADServiceAccount -Properties PrincipalsAllowedToRetrieveManagedPassword | Get-DomainObject -LDAPFilter "(objectClass=msDS-GroupManagedServiceAccount)" |
| DCSync rights | Get-Acl "AD:\<domainDN>" (replication GUIDs) | Get-DomainObjectAcl -SearchBase <domainDN> -ResolveGUIDs |
| Password not required | UAC bit 32 filter | Get-DomainUser -UACFilter PASSWD_NOTREQD |
| Computers by OS | (operatingSystem=*2012*) | Get-DomainComputer -OperatingSystem "*2012*" |
[!tip] The habit to build Ask “what object and which attribute do I actually want?”, write the
-LDAPFilterfor it, add-Propertiesfor the attributes, and-SearchBaseto scope it. That single targeted query — native, signed, already present — is almost always the answer, deleted objects included.
Troubleshooting
| Problem | Cause & fix |
|---|---|
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 |
| 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 |
-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 |
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 |
| Attribute you asked for is blank | It is not in the default property set. Add it explicitly: -Properties memberof,servicePrincipalName,lastLogonTimestamp |
lastLogonTimestamp looks wrong | It is replicated only every ~14 days by design. For precise timing you need per-DC lastLogon, which does not replicate |
| ADSI works locally but fails from a foothold shell | No Kerberos/NTLM context. Pass explicit creds to the DirectoryEntry, or run under runas /netonly |
See Also
- PowerView & PowerUp — the offensive toolkit whose queries this sheet maps to native equivalents of.
- BloodHound — graph the relationships once you have collected the objects.
- AD Recycle Bin Enumeration — the deleted-object corner of the same directory.
- Kerberoasting — act on the SPN-bearing accounts these filters surface.