AD^:Active Directory

Active Directory Enumeration — Native Tooling

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.

intermediateupdated 2026-09-25ActiveDirectory module (Get-AD*) · ldapsearch · ADSI / adsisearcher · dsquery

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 (with runas /netonly), that is how you query without being joined.

The core cmdlets

CmdletAnswers
Get-ADUserusers + attributes (SPNs, UAC flags, lastLogon, description)
Get-ADGroup / Get-ADGroupMembergroups; who is IN a group (-Recursive for nested)
Get-ADComputercomputers; OS, delegation, lastLogon
Get-ADObjectany object by LDAP filter — the universal tool (incl. deleted)
Get-ADDomain / Get-ADForestfunctional level, naming contexts, FSMO
Get-ADTrusttrust relationships (direction, transitivity)
Get-ADServiceAccount(g)MSAs and who may retrieve the password
Get-ADOrganizationalUnitOU 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 $true bare; 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 bitValueMeaning
0x00022Account disabled
0x002032Password not required
0x0200512Normal account
0x1000065536Password never expires
0x80000524288Trusted for delegation (unconstrained)
0x1000001048576Not delegated (sensitive)
0x4000004194304Does not require Kerberos pre-auth
0x001016Account locked out (transient)
0x004064Password can’t change
0x0080128Reversible (cleartext) password storage allowed
0x20008192Server trust account (domain controller)
0x40000262144Smart-card required for interactive logon
0x2000002097152Use DES keys only (weak Kerberos / downgrade)
0x8000008388608Password expired
0x100000016777216Trusted to auth for delegation (constrained + protocol transition / S4U2Self)
0x400000067108864Partial 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 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”.

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) 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.

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> or nxc 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
PropertyReading it
DirectionInbound (they trust us), Outbound (we trust them), BiDirectional
IntraForestTrue = parent/child inside one forest (SID filtering off by default → SID-history viable)
ForestTransitiveTrue = trust to a separate forest
SIDFilteringQuarantinedTrue = SID filtering ON, injected SID-history dropped; False = injection viable
SIDFilteringForestAwareforest-boundary SID-filtering state (nuanced — read alongside TrustAttributes)
SelectiveAuthenticationTrue = 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 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.
  • 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.
  • 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.
  • 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-ManagedPassword is 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 -x on 389 shows up here.

Native vs PowerView — quick map

TaskNativePowerView
Find users/computersGet-ADUser / Get-ADComputer -Filter/-LDAPFilterGet-DomainUser / Get-DomainComputer
Group membershipGet-ADGroupMember -RecursiveGet-DomainGroupMember -Recurse
SPNs (kerberoast)(servicePrincipalName=*)Get-DomainUser -SPN
AS-REP roastableUAC bit 4194304 filterGet-DomainUser -PreauthNotRequired
Deleted objectsGet-ADObject -IncludeDeletedObjects(n/a — use native)
TrustsGet-ADTrust -Filter *Get-DomainTrust
DelegationmsDS-AllowedToDelegateTo / TrustedForDelegationGet-DomainComputer -Unconstrained
Object ACLsGet-Acl "AD:\<DN>"Get-DomainObjectAcl (easier)
GPO to OU mappingGet-GPO / Get-GPInheritance (GroupPolicy module)Get-DomainGPO / Get-DomainOU
LAPS read(ms-Mcs-AdmPwd=*) / Get-LapsADPasswordGet-DomainComputer -Properties ms-Mcs-AdmPwd
gMSA readGet-ADServiceAccount -Properties PrincipalsAllowedToRetrieveManagedPasswordGet-DomainObject -LDAPFilter "(objectClass=msDS-GroupManagedServiceAccount)"
DCSync rightsGet-Acl "AD:\<domainDN>" (replication GUIDs)Get-DomainObjectAcl -SearchBase <domainDN> -ResolveGUIDs
Password not requiredUAC bit 32 filterGet-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 -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.

Troubleshooting

ProblemCause & fix
Get-ADUser : term not recognizedThe 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 nothingYou 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 expectedThe default page size caps results. The AD cmdlets page automatically; raw ADSI/DirectorySearcher does not — set .PageSize = 1000
A referral was returned from the serverThe 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 blankIt is not in the default property set. Add it explicitly: -Properties memberof,servicePrincipalName,lastLogonTimestamp
lastLogonTimestamp looks wrongIt 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 shellNo Kerberos/NTLM context. Pass explicit creds to the DirectoryEntry, or run under runas /netonly

See Also

On this page

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.