🏢Active DirectoryComputersMonitoring

Active Directory Domain Controller Computer Object Hygiene LAPS Schema: Six Gaps a Live Audit Keeps Finding

Active Directory domain controller computer object hygiene laps schema gaps most audits miss: an unextended LAPS schema, misplaced DCs, stale computers, and machine passwords that stopped rotating.

Younes AZABARBy Younes AZABAR9 min read
Active Directory Domain Controller Computer Object Hygiene LAPS Schema: Six Gaps a Live Audit Keeps Finding

Active Directory Domain Controller Computer Object Hygiene LAPS Schema: What This Audit Covers

Active Directory domain controller computer object hygiene laps schema checks are what a live audit finds first, and none of them are individually dramatic: an AD schema that was never extended for LAPS, domain controllers sitting outside their OU, and computer objects nobody has looked at in years. Together they sit underneath the headline attack paths — Kerberoasting, DCSync, ADCS escalation — and quietly determine whether those attacks are even necessary. A domain where every computer object is current, every domain controller sits where it should, and local administrator passwords are centrally managed is a domain where an attacker has to work for a foothold. A domain where none of that is true hands out shortcuts.

This piece covers six gaps that a live audit against a real AD environment consistently turns up together, none of which show up in a typical "top 10 misconfigurations" list because none of them are a single dramatic vulnerability:

  1. The LAPS Active Directory schema extension has never been applied — not "LAPS is deployed but not everywhere," the schema attributes themselves don't exist.
  2. Domain controllers whose computer object lives outside the Domain Controllers OU.
  3. Domain controller objects that stopped replicating and were never cleaned up.
  4. Stale, inactive computer objects with no owner watching them.
  5. Computers without BitLocker, including domain controllers holding NTDS.dit.
  6. Computer accounts whose machine password stopped rotating.

Each one is individually low-drama. Together they describe an environment where object lifecycle is nobody's job — and that's exactly the condition attackers rely on when the flashier controls are already locked down.

Why an Unextended LAPS Schema Is the Deepest Gap

Local Administrator Password Solution comes in two generations, and the distinction matters here. Legacy Microsoft LAPS stored the managed password in the ms-Mcs-AdmPwd attribute, added to the schema by running Update-AdmPwdADSchema as a Schema Admin — see Microsoft's own attribute reference in MS-ADA2. Since the April 2023 cumulative update, Windows LAPS ships as a built-in OS component and uses a different, encrypted set of attributes (msLAPS-Password, msLAPS-EncryptedPassword, msLAPS-PasswordExpirationTime) — see the Windows LAPS technical reference. Either generation requires its own one-time schema extension (Update-LapsADSchema for the new attributes), run once, domain-wide, by someone in Schema Admins.

That step is easy to skip because skipping it produces no error. GPOs can be linked, the LAPS CSE can be pushed to every endpoint, and nothing will happen — there is no attribute to write the password into. This is a different and more fundamental gap than "LAPS is configured but some computers aren't in scope," which is the Windows LAPS Not Deployed gap we've covered separately. Here, the schema itself was never touched, which means every local administrator password in the domain is unmanaged — commonly shared identically across a build image, per ADSecurity.org's LAPS deployment analysis. One image-based local admin credential, once cracked or dumped from a single low-value workstation, unlocks lateral movement into every machine built from that image.

DCs Outside Their OU and Metadata Nobody Cleaned Up

DC_NOT_IN_DC_OU looks cosmetic until you check what Microsoft actually links to the default Domain Controllers OU: the Default Domain Controllers Policy GPO, which sets DC-specific user rights assignments, audit policy, and security options — the same GPO-inheritance chain we dig into in GPO Misconfigurations: How Group Policy Becomes an Attack Vector. Moving a domain controller's computer object into a different OU — even a child OU created for organizational tidiness — breaks that inheritance chain, and Microsoft has documented this as an unsupported configuration for years, not a stylistic preference; see Computerworld's writeup on the mistake and Semperis' domain controller security guide. A DC that quietly lost its baseline audit policy is a DC generating incomplete security logs — which is also exactly the kind of blind spot a rogue-DC registration technique like DCShadow depends on; we cover that specific abuse in DCShadow Attack: Rogue Domain Controller Registration.

DC_INACTIVE is the sibling problem: a DC computer object that stopped replicating and was never formally decommissioned. Microsoft's guidance is explicit that a DC removed by hardware failure or a failed forced demotion leaves orphaned directory and DNS metadata — computer and NTDS Settings objects, replication connections, SRV/CNAME records — that has to be removed deliberately via metadata cleanup, not left in place; see Clean up Active Directory Domain Controller server metadata. Left alone, that stale DC identity produces inconsistent DC-locator results and gives an attacker a plausible, rarely-audited object to impersonate or repurpose. Object placement and replication health are the "hygiene" half of DC security; the network-service half — LDAPS cipher strength, an exposed Print Spooler, clock drift past Kerberos tolerance — is a distinct checklist we published in Domain Controller LDAPS Weak TLS, Print Spooler, Time Sync Audit.

Stale Computers, Missing BitLocker, and Machine Passwords Nobody Rotates

COMPUTER_STALE_INACTIVE is the computer-object equivalent of a stale user account: a machine that hasn't authenticated in months but is still a fully valid Kerberos principal with a SID, group memberships, and — if anyone ever granted it delegation rights or write access to something sensitive — an attack surface nobody is watching. The distinct, deeper risks that live on top of a computer object once an attacker controls it (unconstrained delegation, RBCD abuse, DCSync-capable rights) are covered separately in Active Directory Computer Objects Attack Surface; this gap is about the objects existing at all, un-reviewed.

COMPUTER_NO_BITLOCKER matters most on the machines holding the most valuable data at rest. For a domain controller specifically, that's NTDS.dit — the database containing every account's password hash. Microsoft's own domain controller hardening guidance recommends TPM-backed BitLocker on all DC volumes precisely because it protects the directory even if a physical disk is removed from the server (see the Securing Domain Controllers Against Attack reference). When BitLocker is enabled with AD-based key escrow, the recovery password lands as an msFVE-RecoveryInformation child object under the computer object — see Storing BitLocker Recovery Keys in Active Directory — so its absence is directly queryable, not something you have to trust a spreadsheet about.

COMPUTER_PASSWORD_OLD tracks a subtler signal. By default, "Domain member: Maximum machine account password age" is 30 days — every domain-joined computer is expected to rotate its own machine password on that cadence, a setting documented in Microsoft's security policy reference and explained in depth by ADSecurity.org's machine account password walkthrough. A machine account with a password far older than 30 days that's still actively logging on usually means a broken secure channel, not a hardened one — and a static machine password gives an attacker who compromises the account far more time to brute-force or replay it before rotation forces a reset.

Detection

GapWhat to checkQuery / sourceWhat it tells you
COMPUTER_NO_LAPSSchema partition for ms-Mcs-AdmPwd and msLAPS-PasswordGet-ADObject against (Get-ADRootDSE).schemaNamingContextLAPS was never extended into the schema at all
DC_NOT_IN_DC_OUEach DC's distinguishedNameCross-check Get-ADDomainController -Filter * against the Domain Controllers OUDC lost Default Domain Controllers Policy inheritance
DC_INACTIVEReplication currency per DCrepadmin /showrepl * /csv, DFSR/KCC event logDC stopped replicating; likely orphaned metadata
COMPUTER_STALE_INACTIVElastLogonTimestamp ageGet-ADComputer -Properties lastLogonTimestampMachine hasn't authenticated in 90+ days
COMPUTER_NO_BITLOCKERmsFVE-RecoveryInformation child objectLDAP query scoped to each computer's DNNo recovery key escrowed → volume likely unencrypted
COMPUTER_PASSWORD_OLDpwdLastSet / PasswordLastSetGet-ADComputer -Properties PasswordLastSet, Event ID 4742Machine password rotation has stalled
# 1. Confirm the LAPS schema extension exists (either generation)
Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext `
    -Filter {name -eq "ms-Mcs-AdmPwd" -or name -eq "msLAPS-Password"}

# 2. Domain controllers whose computer object lives outside the default DC OU
Get-ADDomainController -Filter * | ForEach-Object {
    $dn = (Get-ADComputer $_.Name).DistinguishedName
    if ($dn -notmatch "OU=Domain Controllers") { "$($_.Name) -> $dn" }
}

# 3. Stale computer objects — no authentication in 90+ days
Get-ADComputer -Filter * -Properties lastLogonTimestamp |
    Where-Object { [DateTime]::FromFileTime($_.lastLogonTimestamp) -lt (Get-Date).AddDays(-90) } |
    Select-Object Name, @{N='LastLogon';E={[DateTime]::FromFileTime($_.lastLogonTimestamp)}}

# 4. Computers with no BitLocker recovery info escrowed to AD
Get-ADComputer -Filter * | ForEach-Object {
    $recovery = Get-ADObject -Filter {objectClass -eq "msFVE-RecoveryInformation"} -SearchBase $_.DistinguishedName
    if (-not $recovery) { $_.Name }
}

# 5. Machine account password older than the 30-day policy
Get-ADComputer -Filter * -Properties PasswordLastSet |
    Where-Object { $_.PasswordLastSet -lt (Get-Date).AddDays(-30) } |
    Select-Object Name, PasswordLastSet
ℹ️

ℹ️ Note: lastLogonTimestamp replicates domain-wide but lags real activity by up to ~14 days by design — don't treat a borderline result as gospel without cross-checking lastLogon on each DC directly.

Remediation

💡

💡 Quick Win: run the schema check above before anything else — if Get-ADObject returns nothing for both attribute names, every other LAPS-related fix on the network is dead on arrival until a Schema Admin runs Update-LapsADSchema.

1. Extend the LAPS Schema, Once, Domain-Wide

Run Update-LapsADSchema (Windows LAPS) — or Update-AdmPwdADSchema if the org is deliberately staying on legacy LAPS — as a member of Schema Admins, then delegate SELF write on the new attributes with Set-LapsADComputerSelfPermission before rolling the GPO out.

2. Move Misplaced DC Objects Back Into Domain Controllers

Use Move-ADObject or ADUC to relocate the computer object, then confirm the Default Domain Controllers Policy re-applies with gpresult /r on the affected DC.

3. Resolve or Retire Inactive DCs Deliberately

If repadmin /showrepl shows a genuine replication failure, fix it. If the DC is actually gone, run a proper metadata cleanup instead of leaving the orphaned object and DNS records in place.

4. Disable, Then Delete, Stale Computers on a Fixed Schedule

For example, disable at 90 days of inactivity and delete at 180 — the same discipline already applied to stale user accounts.

5. Enable BitLocker With TPM and AD Key Escrow

Prioritize domain controllers first, via the "Store BitLocker recovery information in Active Directory Domain Services" GPO setting, so msFVE-RecoveryInformation populates and becomes auditable.

6. Leave the 30-Day Machine Password Age Policy Alone

Investigate rather than ignore any active machine whose PasswordLastSet has drifted well past it — usually Test-ComputerSecureChannel -Repair fixes a broken secure channel that's silently blocking rotation.

How EtcSec Detects This

EtcSec's Active Directory audit checks all six of these conditions directly against the domain: COMPUTER_NO_LAPS for a missing schema extension, DC_NOT_IN_DC_OU and DC_INACTIVE for domain controller placement and replication health, COMPUTER_STALE_INACTIVE for unreviewed dormant machines, COMPUTER_NO_BITLOCKER for unescrowed disk encryption, and COMPUTER_PASSWORD_OLD for stalled machine password rotation.

ℹ️

ℹ️ Note: EtcSec automatically checks for this vulnerability during every AD/Azure audit. Run a free audit to verify your environment.

Explore the identity security pages that support this topic