Dormant accounts and shared accounts are two of the most common identity-control gaps in Active Directory and hybrid environments. They create audit findings because they weaken accountability (who did what?) and increase attack surface (stale credentials, over-permissioning, and silent persistence).
What “Dormant” and “Shared” Really Mean
Dormant accounts
- User accounts that have not authenticated for an agreed time window (e.g., 30/60/90+ days).
- Service and application accounts that are still enabled but no longer used by a workload.
- Ex-employees / contractors whose accounts remain enabled due to process gaps or poor HR sync.
Shared accounts
- Generic logins used by multiple humans (e.g., “helpdesk”, “store01”, “reception”).
- Kiosk / shift accounts used across teams for operational convenience.
- Break-glass / emergency admin accounts (valid use case, but still “shared” in practice if not controlled).
- Legacy service accounts used interactively by humans because “it already has access.”
Compliance issue in one sentence: shared accounts destroy individual accountability, and dormant accounts increase unauthorized access risk because they are rarely monitored but often still privileged.
Compliance Outcomes Auditors Expect
Most frameworks differ in wording, but audits converge on the same identity outcomes:
- Unique identity: individuals authenticate with named accounts, not shared credentials.
- Lifecycle governance: timely deprovisioning and disabling of unused identities.
- Least privilege: access is justified, minimal, and reviewed on a schedule.
- Traceability: logs can attribute actions to a person (or a controlled system identity).
- Exception control: when shared or long-lived accounts must exist, they are documented, approved, and monitored.
Build a Practical Control Policy
1) Define dormancy thresholds (by account type)
- Standard user: flag at 30 days, disable at 60 days, remove licenses/access at 60–90 days.
- Privileged user: flag at 7–14 days, disable at 30 days (or sooner), require immediate investigation.
- Service accounts: “dormant” should be based on workload telemetry (service start/auth logs), not just AD logon.
- Break-glass: should be “unused by design,” but tested on a schedule and monitored for any real use.
2) Establish a “shared account exception” standard
Ideally, shared human logins are eliminated. Where exceptions are allowed, enforce these minimum controls:
- Business justification and named owner (not a team, a person accountable for it).
- Time-bound approval (e.g., 90-day renewal with review).
- Restrictive logon conditions: limited devices, limited hours, and deny interactive logon if not required.
- Credential protection: password vaulting + rotation (and MFA where possible).
- Enhanced monitoring: alerts for sign-in, group membership change, and privileged activity.
3) Standardize evidence artifacts
- Account inventory with type classification (user, admin, service, shared, break-glass).
- Owner / sponsor mapping and approval record.
- Last activity evidence (auth logs) and disablement workflow history.
- Quarterly (or more frequent) access review output with remediation notes.
Detect Dormant Accounts Reliably in Active Directory
Use the right signals
- lastLogonTimestamp: replicated, good for “inactive since ~X days” (approximate).
- lastLogon: accurate but not replicated (must query each DC and take the latest).
- pwdLastSet and whenChanged: useful supporting signals (stale passwords, recent admin touches).
- Event logs / SIEM: the best “proof of use” for privileged and sensitive systems.
Quick PowerShell inventory (dormant users)
# Requires RSAT ActiveDirectory module
# Flags enabled users inactive for 60+ days using lastLogonTimestamp.
$DaysInactive = 60
$Cutoff = (Get-Date).AddDays(-$DaysInactive)
Get-ADUser -Filter { Enabled -eq $true -and lastLogonTimestamp -lt $Cutoff } `
-Properties lastLogonTimestamp, whenCreated, pwdLastSet, Description, Department, Manager `
| Select-Object Name, SamAccountName,
@{n="LastLogonApprox";e={[DateTime]::FromFileTime($_.lastLogonTimestamp)}},
@{n="PwdLastSet";e={[DateTime]::FromFileTime($_.pwdLastSet)}},
whenCreated, Department, Manager, Description
| Sort-Object LastLogonApprox
| Export-Csv ".\DormantUsers_60Days.csv" -NoTypeInformation
Better accuracy (query all DCs)
For high-risk scopes (admins, servers, sensitive apps), query lastLogon across domain controllers and take the newest value.
# Accurate lastLogon across all DCs (slower but better for privileged accounts)
$DaysInactive = 30
$Cutoff = (Get-Date).AddDays(-$DaysInactive)
$DCs = (Get-ADDomainController -Filter *).HostName
$Users = Get-ADUser -LDAPFilter "(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" `
-Properties lastLogon, memberOf
$Results = foreach ($u in $Users) {
$maxLogon = 0
foreach ($dc in $DCs) {
$ll = (Get-ADUser $u.SamAccountName -Server $dc -Properties lastLogon).lastLogon
if ($ll -gt $maxLogon) { $maxLogon = $ll }
}
$last = if ($maxLogon -gt 0) { [DateTime]::FromFileTime($maxLogon) } else { $null }
[pscustomobject]@{
SamAccountName = $u.SamAccountName
LastLogon = $last
InactiveOver = $DaysInactive
IsInactive = ($last -eq $null -or $last -lt $Cutoff)
}
}
$Results | Where-Object IsInactive | Export-Csv ".\DormantUsers_Accurate.csv" -NoTypeInformation
Control Shared Accounts Instead of Hoping They Behave
Preferred approach: remove shared human logins
- Use named accounts for all humans.
- Use delegation (RBAC via groups) instead of handing out a “powerful shared credential.”
- Use privileged elevation (JIT/PIM/PAM) so admin access is time-bound and attributable.
When shared accounts must exist (minimum hardening)
- Limit logon workstations (AD user property “Log On To…” or GPO).
- Deny interactive logon where not needed (Deny log on locally / through RDP).
- Restrict network access (firewall rules, SMB restrictions, app allow-lists).
- Rotate credentials frequently and automatically via a vault.
- Remove from privileged groups unless absolutely required; use scoped delegation instead.
- Strong monitoring: alert on any sign-in, group membership change, password reset, and privilege use.
Service account modernization (big compliance win)
- For on-prem Windows services: prefer gMSA (no human-known password, auto-managed rotation).
- For cloud workloads: prefer managed identities or workload identity federation.
- Make service accounts non-interactive and scoped to only required hosts and permissions.
Operational Workflow: Detect → Quarantine → Disable → Delete
Step 1: Detect and classify
- Detect inactivity and create a candidate list.
- Classify each account: user / privileged / service / shared / break-glass.
- Identify owner and system dependencies (apps, scheduled tasks, services).
Step 2: Quarantine for safe validation
- Move to a dedicated Quarantine OU with stricter policies (no interactive logon, no VPN, minimal access).
- Tag clearly (Description field): reason, date, ticket/approval reference, owner.
- Monitor for authentication attempts during a short observation window.
Step 3: Disable and remove access
- Disable account after policy threshold.
- Remove from sensitive groups; revoke application access where feasible.
- In hybrid: remove or block licenses to reduce cost and risk exposure.
Step 4: Delete with retention discipline
- After retention (commonly 90–180 days, depending on legal/regulatory needs), delete or archive appropriately.
- Keep evidence: who approved, when disabled, when deleted, and why.
Monitoring and Evidence: What to Alert On
Dormant and shared account compliance fails most often because visibility is weak. At minimum, alert on:
- Any interactive logon by a shared or break-glass account.
- New account creation outside approved provisioning channels.
- Group membership changes for privileged groups.
- Password resets on shared, privileged, or service accounts.
- Unexpected host logons (account used from a workstation/server it shouldn’t touch).
Practical logging tips
- Enable advanced auditing for logon and account management events via GPO.
- Forward domain controller security events to a SIEM or central collector.
- Use change-auditing solutions to keep a readable trail of “who changed what” in AD (especially for groups and GPOs).
Access Reviews That Don’t Waste Everyone’s Time
Access reviews become meaningful when they are targeted and outcome-driven:
- Scope smartly: privileged accounts, shared accounts, service accounts, and high-risk OUs first.
- Pre-fill evidence: last sign-in, group memberships, resource access, and owner.
- Force decisions: keep, reduce access, disable, or convert (e.g., shared → named accounts).
- Measure remediation: track closure rate and time-to-disable.
Common Pitfalls (and How to Avoid Them)
-
Pitfall: Relying only on
lastLogonTimestampfor privileged accounts.
Fix: Use accurate DC queries or SIEM sign-in data for high-risk scopes. -
Pitfall: Disabling accounts without checking dependencies (scheduled tasks, services, scripts).
Fix: Inventory service dependencies; transition to gMSA/managed identities where possible. -
Pitfall: “Shared account” exceptions with no expiration date.
Fix: Make exceptions time-bound and require renewal with evidence and owner sign-off. -
Pitfall: Shared accounts used for admin work because it’s convenient.
Fix: Implement named admin accounts, JIT elevation, and strong auditing for privileged actions.
Implementation Checklist
- Define dormancy thresholds by account type and document them.
- Create account classification tags (user/admin/shared/service/break-glass) and enforce owner fields.
- Automate inactive-account reports and route them to a ticket workflow.
- Implement a Quarantine OU and a standard disablement/deletion timeline.
- Eliminate shared human logins; where unavoidable, harden, vault, rotate, and monitor.
- Migrate service identities to gMSA/managed identities and deny interactive logon.
- Centralize logging and alert on shared/break-glass usage and privileged group changes.
- Run targeted access reviews with clear remediation outcomes.


