{
  "title": "How to Configure Active Directory to Disable Dormant Accounts Automatically — Practical Implementation for NIST SP 800-171 REV.2 / CMMC 2.0 Level 2 - Control - IA.L2-3.5.6",
  "date": "2026-04-12",
  "author": "Lakeridge Technologies",
  "featured_image": "/assets/images/blog/2026/4/how-to-configure-active-directory-to-disable-dormant-accounts-automatically-practical-implementation-for-nist-sp-800-171-rev2-cmmc-20-level-2-control-ial2-356.jpg",
  "content": {
    "full_html": "<p>Disabling dormant accounts automatically in Active Directory closes a common persistence vector attackers use and is a tangible control to meet NIST SP 800-171 Rev.2 / CMMC 2.0 Level 2 control IA.L2-3.5.6; this post shows practical, repeatable steps to implement detection and automated disablement, including real-world examples for small businesses, scripts, scheduling, and operational safeguards.</p>\n\n<h2>Understanding the requirement and the risk of non-implementation</h2>\n<p>IA.L2-3.5.6 requires organizations to prevent inactive accounts from becoming long-term footholds for adversaries — an account that hasn’t been used for weeks or months can be exploited for lateral movement or data exfiltration. Failing to identify and remediate dormant accounts increases the risk of unauthorized access, extended dwell time for attackers, lost contracts or penalties for non-compliance, and reputational damage if a breach arises from unused credentials.</p>\n\n<h2>Implementation overview for Active Directory (on-prem)</h2>\n<h3>Define dormancy thresholds and policy</h3>\n<p>Start by documenting an organizational policy: define what “dormant” means (e.g., no interactive logon in 60 or 90 days), which accounts are in scope (user, service, admin), and the remediation workflow (notification → disable → quarantine OU → deletion after retention period). Typical small-business practice is 90 days for standard users and 30–60 days for privileged accounts, but your policy must align with business risk and NIST/CMMC expectations.</p>\n\n<h3>Choose the right detection signal</h3>\n<p>For on-prem AD, use the lastLogonTimestamp attribute (replicated) for broad scans and lastLogon (per-DC) if you need per-DC precision. Note lastLogonTimestamp is updated only when logon is sufficiently old (default ~9–14 days), so it’s reliable for multi-week inactivity checks but not for last-hour accuracy. For hybrid environments, supplement with Azure AD/Entra Sign-in logs or conditional access reports.</p>\n\n<h3>Automated remediation — recommended PowerShell pattern</h3>\n<p>Automate with a scheduled PowerShell runbook on a management server with the ActiveDirectory module installed. Key technical points: run as a dedicated service account with delegated rights (Account Operators or explicit deny/allow), filter out service/admin accounts (use attributes like PasswordNeverExpires, Description tags, or membership in an “ExcludeFromDormancy” group), log every action to a central SIEM or CSV, generate a ticket/notification before final disable, and move disabled accounts to a quarantined OU.</p>\n\n<pre><code># Example: disable users not logged on in last 90 days (run with AD module)\nImport-Module ActiveDirectory\n$threshold = (Get-Date).AddDays(-90)\n$excludeGroups = @(\"Domain Admins\",\"ServiceAccountsExclude\")\n$disabledOU = \"OU=Disabled Users,DC=contoso,DC=com\"\n\nGet-ADUser -Filter * -Properties LastLogonTimeStamp,Enabled,PasswordNeverExpires |\n  Where-Object {\n    $_.Enabled -eq $true -and\n    -not $_.PasswordNeverExpires -and\n    ($_.LastLogonTimeStamp -ne $null) -and\n    ([DateTime]::FromFileTime($_.LastLogonTimeStamp) -lt $threshold)\n  } | ForEach-Object {\n    # skip excluded group members\n    if((Get-ADUser $_ -Properties memberOf).memberOf -notin $excludeGroups) {\n      # log action\n      \"$((Get-Date).ToString('s')) DISABLING: $($_.SamAccountName)\" | Out-File C:\\Scripts\\dormant-disable.log -Append\n      # disable and move to quarantine OU\n      Disable-ADAccount -Identity $_.DistinguishedName\n      Move-ADObject -Identity $_.DistinguishedName -TargetPath $disabledOU\n      # optionally add description and create ticket/alert\n      Set-ADUser -Identity $_.DistinguishedName -Description \"Disabled by dormancy automation on $((Get-Date).ToString('yyyy-MM-dd'))\"\n    }\n  }\n</code></pre>\n\n<h2>Operational steps: scheduling, notifications, and audit</h2>\n<p>Run the automation as a scheduled task or Azure Automation runbook nightly or weekly depending on the threshold. Build a notification queue: pre-disable email to account owner and manager (e.g., 7-day notice), automatic ticket creation for each disablement, and a review step before permanent deletion (retain disabled accounts for your retention period, e.g., 30 days). Ensure every change writes to a central log and that AD audits are enabled (enable success/failure auditing for Account Management events) so your compliance evidence includes who/when/what.</p>\n\n<h2>Practical small-business scenarios and examples</h2>\n<p>Example A — Small engineering firm (50 users): implement a 90-day dormancy threshold. Use a group-based exclusion for shared service accounts and put highly privileged accounts in a separate OU to require manual review before disablement. Example B — Small MSP (100+ employees): integrate the script with the ticketing system (e.g., ServiceNow, Jira) using API calls so a ticket is automatically generated for each disabled account and a helpdesk tech verifies if the account belongs to a contractor or long-term absence before reinstating. These simple integrations prevent business disruption while satisfying auditors.</p>\n\n<h2>Compliance tips and best practices</h2>\n<p>Follow these best practices: maintain a documented policy that ties dormancy thresholds to business risk; exclude service and application accounts (then track and rotate their credentials regularly); use quarantined OUs and clear naming (prefix \"DISABLED_\"); keep an immutable audit trail (SIEM ingestion or append-only logs); periodically review exclusions and automation logic; and test the automation in a staging OU before production rollout. Additionally, combine this with MFA and conditional access to reduce risk from overlooked accounts.</p>\n\n<p>In summary, implementing automatic disablement of dormant Active Directory accounts is a highly practical control to meet IA.L2-3.5.6: define clear policies, select appropriate logon attributes, automate detection and remediation with careful exclusions and notifications, log every action for audit, and integrate with operational processes. With modest scripting, scheduled automation, and a policy-driven approach, small businesses can significantly reduce account-based attack surface while producing the evidence needed for NIST SP 800-171 Rev.2 / CMMC 2.0 compliance.</p>",
    "plain_text": "Disabling dormant accounts automatically in Active Directory closes a common persistence vector attackers use and is a tangible control to meet NIST SP 800-171 Rev.2 / CMMC 2.0 Level 2 control IA.L2-3.5.6; this post shows practical, repeatable steps to implement detection and automated disablement, including real-world examples for small businesses, scripts, scheduling, and operational safeguards.\n\nUnderstanding the requirement and the risk of non-implementation\nIA.L2-3.5.6 requires organizations to prevent inactive accounts from becoming long-term footholds for adversaries — an account that hasn’t been used for weeks or months can be exploited for lateral movement or data exfiltration. Failing to identify and remediate dormant accounts increases the risk of unauthorized access, extended dwell time for attackers, lost contracts or penalties for non-compliance, and reputational damage if a breach arises from unused credentials.\n\nImplementation overview for Active Directory (on-prem)\nDefine dormancy thresholds and policy\nStart by documenting an organizational policy: define what “dormant” means (e.g., no interactive logon in 60 or 90 days), which accounts are in scope (user, service, admin), and the remediation workflow (notification → disable → quarantine OU → deletion after retention period). Typical small-business practice is 90 days for standard users and 30–60 days for privileged accounts, but your policy must align with business risk and NIST/CMMC expectations.\n\nChoose the right detection signal\nFor on-prem AD, use the lastLogonTimestamp attribute (replicated) for broad scans and lastLogon (per-DC) if you need per-DC precision. Note lastLogonTimestamp is updated only when logon is sufficiently old (default ~9–14 days), so it’s reliable for multi-week inactivity checks but not for last-hour accuracy. For hybrid environments, supplement with Azure AD/Entra Sign-in logs or conditional access reports.\n\nAutomated remediation — recommended PowerShell pattern\nAutomate with a scheduled PowerShell runbook on a management server with the ActiveDirectory module installed. Key technical points: run as a dedicated service account with delegated rights (Account Operators or explicit deny/allow), filter out service/admin accounts (use attributes like PasswordNeverExpires, Description tags, or membership in an “ExcludeFromDormancy” group), log every action to a central SIEM or CSV, generate a ticket/notification before final disable, and move disabled accounts to a quarantined OU.\n\n# Example: disable users not logged on in last 90 days (run with AD module)\nImport-Module ActiveDirectory\n$threshold = (Get-Date).AddDays(-90)\n$excludeGroups = @(\"Domain Admins\",\"ServiceAccountsExclude\")\n$disabledOU = \"OU=Disabled Users,DC=contoso,DC=com\"\n\nGet-ADUser -Filter * -Properties LastLogonTimeStamp,Enabled,PasswordNeverExpires |\n  Where-Object {\n    $_.Enabled -eq $true -and\n    -not $_.PasswordNeverExpires -and\n    ($_.LastLogonTimeStamp -ne $null) -and\n    ([DateTime]::FromFileTime($_.LastLogonTimeStamp) -lt $threshold)\n  } | ForEach-Object {\n    # skip excluded group members\n    if((Get-ADUser $_ -Properties memberOf).memberOf -notin $excludeGroups) {\n      # log action\n      \"$((Get-Date).ToString('s')) DISABLING: $($_.SamAccountName)\" | Out-File C:\\Scripts\\dormant-disable.log -Append\n      # disable and move to quarantine OU\n      Disable-ADAccount -Identity $_.DistinguishedName\n      Move-ADObject -Identity $_.DistinguishedName -TargetPath $disabledOU\n      # optionally add description and create ticket/alert\n      Set-ADUser -Identity $_.DistinguishedName -Description \"Disabled by dormancy automation on $((Get-Date).ToString('yyyy-MM-dd'))\"\n    }\n  }\n\n\nOperational steps: scheduling, notifications, and audit\nRun the automation as a scheduled task or Azure Automation runbook nightly or weekly depending on the threshold. Build a notification queue: pre-disable email to account owner and manager (e.g., 7-day notice), automatic ticket creation for each disablement, and a review step before permanent deletion (retain disabled accounts for your retention period, e.g., 30 days). Ensure every change writes to a central log and that AD audits are enabled (enable success/failure auditing for Account Management events) so your compliance evidence includes who/when/what.\n\nPractical small-business scenarios and examples\nExample A — Small engineering firm (50 users): implement a 90-day dormancy threshold. Use a group-based exclusion for shared service accounts and put highly privileged accounts in a separate OU to require manual review before disablement. Example B — Small MSP (100+ employees): integrate the script with the ticketing system (e.g., ServiceNow, Jira) using API calls so a ticket is automatically generated for each disabled account and a helpdesk tech verifies if the account belongs to a contractor or long-term absence before reinstating. These simple integrations prevent business disruption while satisfying auditors.\n\nCompliance tips and best practices\nFollow these best practices: maintain a documented policy that ties dormancy thresholds to business risk; exclude service and application accounts (then track and rotate their credentials regularly); use quarantined OUs and clear naming (prefix \"DISABLED_\"); keep an immutable audit trail (SIEM ingestion or append-only logs); periodically review exclusions and automation logic; and test the automation in a staging OU before production rollout. Additionally, combine this with MFA and conditional access to reduce risk from overlooked accounts.\n\nIn summary, implementing automatic disablement of dormant Active Directory accounts is a highly practical control to meet IA.L2-3.5.6: define clear policies, select appropriate logon attributes, automate detection and remediation with careful exclusions and notifications, log every action for audit, and integrate with operational processes. With modest scripting, scheduled automation, and a policy-driven approach, small businesses can significantly reduce account-based attack surface while producing the evidence needed for NIST SP 800-171 Rev.2 / CMMC 2.0 compliance."
  },
  "metadata": {
    "description": "Step-by-step guidance to automatically detect and disable dormant Active Directory accounts to satisfy NIST SP 800-171 Rev.2 / CMMC 2.0 Level 2 control IA.L2-3.5.6 while minimizing business disruption.",
    "permalink": "/how-to-configure-active-directory-to-disable-dormant-accounts-automatically-practical-implementation-for-nist-sp-800-171-rev2-cmmc-20-level-2-control-ial2-356.json",
    "categories": [],
    "tags": []
  }
}