🎁 New User? Get 20% off your first purchase with code NEWUSER20 Register Now →
Menu

Categories

Active Directory Password Policy Audit with PowerShell (2026)

Active Directory Password Policy Audit with PowerShell (2026)
Active Directory password policy audit with PowerShell - Dargslan 2026

"The default domain password policy is 14 characters, complexity on, max age 90 days." That sentence is the audit answer most administrators give. It is also incomplete. Active Directory has supported Fine Grained Password Policies (FGPP) since 2008, and in any organisation older than five years there is at least one PSO that lowers the bar for a service account, a developer group or "the ops team". On top of that, every domain accumulates accounts with PasswordNeverExpires, accounts that have not logged in for two years and were never disabled, and lockout settings copied from a 2010 template.

This guide walks through a full AD password audit from PowerShell, includes the scoring rule we use in client engagements, and ships the Dargslan.AdPasswordAudit module plus a free PDF cheat sheet.

Step 1: Default domain policy

Import-Module ActiveDirectory
Get-ADDefaultDomainPasswordPolicy | Select MinPasswordLength,
    ComplexityEnabled, MaxPasswordAge, MinPasswordAge,
    PasswordHistoryCount, ReversibleEncryptionEnabled,
    LockoutThreshold, LockoutDuration, LockoutObservationWindow

The 2026 baseline most frameworks expect: minimum length 14, complexity on, history at least 24, reversible encryption off, lockout threshold between 5 and 10, lockout duration at least 15 minutes. NIST 800-63B has moved away from forced rotation; if your organisation has a documented exception you can run with a longer max age, but it has to be documented.

Step 2: Fine Grained Password Policies

FGPPs override the default policy for specific groups or users by precedence. They are invisible from the GUI unless you go to Active Directory Administrative Center and they are the most common place a "14 character" claim quietly becomes "8 character for the dev OU":

Get-ADFineGrainedPasswordPolicy -Filter * | Select Name,
    Precedence, MinPasswordLength, ComplexityEnabled,
    MaxPasswordAge, AppliesTo

Sort by Precedence ascending — the lowest number wins. If a service-account PSO with precedence 10 sets MinPasswordLength = 8, every account in scope gets the weaker policy regardless of the default.

Step 3: PasswordNeverExpires accounts

This is the single most common AD finding. Service accounts and "VIP" users accumulate this flag and the password is then 7 years old:

Get-ADUser -Filter {Enabled -eq $true -and PasswordNeverExpires -eq $true} `
    -Properties PasswordLastSet | Select SamAccountName, PasswordLastSet

The defensible target is "no more than three, all are gMSA or documented service accounts, all have a password rotation procedure". A list of 200 such accounts is a finding.

Step 4: Stale accounts

$cut = (Get-Date).AddDays(-90)
Get-ADUser -Filter {Enabled -eq $true} -Properties LastLogonDate |
    Where-Object { $_.LastLogonDate -lt $cut } |
    Select SamAccountName, LastLogonDate

LastLogonDate replicates only every 9-14 days, so 90 days is the smallest threshold that does not produce false positives. For a real cleanup pass use 180 days and disable everything that hits.

Step 5: Lockout posture

Three values matter: threshold (5-10 attempts), duration (at least 15 min), observation window (same as duration). A threshold of 0 disables lockout entirely — common on legacy domains, never acceptable in 2026.

A defensible PASS / WARN / FAIL score

  1. Min length ≥ 14 (1 pt)
  2. Complexity enabled (1 pt)
  3. Lockout threshold between 1 and 10 (1 pt)
  4. Reversible encryption off (1 pt)
  5. ≤ 3 PasswordNeverExpires accounts (1 pt)

5/5 PASS, 2-4 WARN, 0-1 FAIL.

Dargslan.AdPasswordAudit module

Install-Module Dargslan.AdPasswordAudit -Scope CurrentUser
Import-Module Dargslan.AdPasswordAudit
Export-DargslanAdPasswordAuditReport -OutDir C:\reports -StaleDays 90

FAQ

Does it need Domain Admin?

No — any authenticated user can read the default policy and FGPP. Stale-account scans need a user with the Read permission on the OUs you care about.

Why does LastLogonDate sometimes look stale?

It is replicated from lastLogonTimestamp on a 9-14 day jitter. Anything within two weeks of "now" is current.

How do I rotate a gMSA password?

You don't — AD rotates it automatically every 30 days. The presence of PasswordNeverExpires on a real $-suffixed gMSA account is normal.

Cheat sheet?

Free PDF at /cheat-sheets/ad-password-policy-audit-2026.

Related Dargslan resources

Share this article:
Dargslan Editorial Team (Dargslan)
About the Author

Dargslan Editorial Team (Dargslan)

Collective of Software Developers, System Administrators, DevOps Engineers, and IT Authors

Dargslan is an independent technology publishing collective formed by experienced software developers, system administrators, and IT specialists.

The Dargslan editorial team works collaboratively to create practical, hands-on technology books focused on real-world use cases. Each publication is developed, reviewed, and...

Programming Languages Linux Administration Web Development Cybersecurity Networking

Stay Updated

Subscribe to our newsletter for the latest tutorials, tips, and exclusive offers.