Active Directory Fine-Grained Password Policies: How to Deploy Password Settings Objects That Actually Override the Default Domain Policy

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
The default domain password policy is a single policy that applies to every account in the domain. Most organizations need at minimum three different policies: one for standard users, a stricter one for privileged admin accounts, and a specialized one for service accounts that does not expire but requires very high complexity. Fine-Grained Password Policies (PSOs) provide this granularity without touching the default domain policy. The most common implementation mistakes are applying PSOs to OUs (which does not work) and not understanding precedence when multiple PSOs target the same user.
PSO Requirements and Limitations
Before creating PSOs, understand the constraints:
Domain functional level: PSOs require Windows Server 2008 domain functional level or higher. Verify: Get-ADDomain | Select-Object DomainMode
Applies to: PSOs can be applied to global security groups or directly to user/inetOrgPerson objects. They cannot be applied to OUs, computer objects, or distribution groups. This is the most common misconfiguration -- admins apply PSOs to OUs expecting all users in the OU to inherit the policy, but OU application is ignored.
Shadow groups for OU-based targeting: To effectively apply a PSO to all users in an OU, create a global security group (shadow group) and use a scheduled script or dynamic group mechanism to keep the shadow group membership synchronized with the OU contents:
# Synchronize shadow group with OU contents (run via scheduled task)
$ouUsers = Get-ADUser -Filter * -SearchBase "OU=ServiceAccounts,DC=domain,DC=com"
$groupMembers = Get-ADGroupMember -Identity "PSO-ServiceAccounts-Shadow"
# Add users in OU but not in group
$toAdd = $ouUsers | Where-Object { $_.SamAccountName -notin $groupMembers.SamAccountName }
$toAdd | ForEach-Object { Add-ADGroupMember -Identity "PSO-ServiceAccounts-Shadow" -Members $_ }
# Remove group members no longer in OU
$toRemove = $groupMembers | Where-Object { $_.SamAccountName -notin $ouUsers.SamAccountName }
$toRemove | ForEach-Object { Remove-ADGroupMember -Identity "PSO-ServiceAccounts-Shadow" -Members $_ -Confirm:$false }
Creating PSOs with PowerShell
The AD Administrative Center GUI supports PSO creation, but PowerShell is more reliable for documenting and reproducing configurations:
# PSO for privileged admin accounts: 20+ char, strict lockout
New-ADFineGrainedPasswordPolicy -Name "PSO-PrivilegedAdmins" `
-Precedence 10 `
-MinPasswordLength 20 `
-PasswordHistoryCount 24 `
-ComplexityEnabled $true `
-ReversibleEncryptionEnabled $false `
-MinPasswordAge (New-TimeSpan -Days 1) `
-MaxPasswordAge (New-TimeSpan -Days 365) `
-LockoutThreshold 3 `
-LockoutObservationWindow (New-TimeSpan -Minutes 30) `
-LockoutDuration (New-TimeSpan -Minutes 0) `
-Description "Password policy for Tier 0 and Tier 1 admin accounts. Ticket: CHG-1234"
# Apply PSO to group
Add-ADFineGrainedPasswordPolicySubject -Identity "PSO-PrivilegedAdmins" `
-Subjects "Domain Admins","PSO-PrivAdmins-Shadow"
# PSO for service accounts: 30+ char, no expiry, no lockout
New-ADFineGrainedPasswordPolicy -Name "PSO-ServiceAccounts" `
-Precedence 20 `
-MinPasswordLength 30 `
-PasswordHistoryCount 12 `
-ComplexityEnabled $true `
-ReversibleEncryptionEnabled $false `
-MinPasswordAge (New-TimeSpan -Days 0) `
-MaxPasswordAge (New-TimeSpan -Days 0) `
-LockoutThreshold 0 `
-LockoutObservationWindow (New-TimeSpan -Minutes 30) `
-LockoutDuration (New-TimeSpan -Minutes 30) `
-Description "Password policy for service accounts. No expiry, no lockout, high complexity."
Add-ADFineGrainedPasswordPolicySubject -Identity "PSO-ServiceAccounts" `
-Subjects "PSO-ServiceAccounts-Shadow"
Note that LockoutThreshold 0 means lockout is disabled. For service accounts, this is appropriate because lockout creates an availability risk for critical services. Pair with PAM vault credential management instead.
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
PSO Precedence: What Wins When Multiple PSOs Apply
When a user is a member of multiple groups that each have a PSO applied, the PSO with the lowest msDS-PasswordSettingsPrecedence value applies. Lower number = higher priority.
Conflict resolution order:
- PSO applied directly to the user object beats any PSO applied via group membership (regardless of precedence value)
- Among group-applied PSOs, the one with the lowest precedence number wins
- If two PSOs have the same precedence number, AD resolves the tie by comparing the PSO GUID (deterministic but unpredictable from an admin perspective -- avoid duplicate precedence values)
Best practice: assign precedence values in gaps of 10 to allow future policies to be inserted between existing ones:
- 10: Tier 0 Admins (Domain Admins, Schema Admins, Enterprise Admins)
- 20: Tier 1 Admins (server admins, backup operators)
- 30: Service accounts
- 40: Standard users (usually handled by default domain policy, so this PSO is only needed if the default domain policy cannot be changed)
Verify precedence is correct by checking the resultant PSO for a sample of users in each category:
Get-ADUserResultantPasswordPolicy -Identity "admin-username" | Format-List Name, Precedence, MinPasswordLength, LockoutThreshold
This reads the msDS-ResultantPSO attribute and returns the fully resolved policy settings in effect for that user.
Verifying Which Policy Is Applied to a User
After creating and assigning PSOs, verify that each user has the correct policy applied:
# Check the resultant PSO for a specific user
Get-ADUserResultantPasswordPolicy -Identity "jsmith"
# If no PSO is applied, this returns nothing and the default domain policy applies
# The user's msDS-ResultantPSO attribute will be null
# Bulk check: show which PSO is applied to each user in a group
Get-ADGroupMember -Identity "Domain Admins" | ForEach-Object {
$user = Get-ADUser -Identity $_.SamAccountName
$pso = Get-ADUserResultantPasswordPolicy -Identity $_.SamAccountName
[PSCustomObject]@{
User = $_.SamAccountName
ResultantPSO = if ($pso) { $pso.Name } else { "Default Domain Policy" }
MinLength = if ($pso) { $pso.MinPasswordLength } else { (Get-ADDefaultDomainPasswordPolicy).MinPasswordLength }
}
} | Format-Table -AutoSize
For service accounts specifically, run this query regularly (monthly) to detect any service account that lost its PSO assignment (e.g., due to shadow group membership desync) and reverted to the default domain policy with password expiry enabled -- which would cause the service to fail at expiry.
Lockout Policy Considerations for Service Accounts
Service account lockout is an operational risk. A service account locked out due to a brute-force or password spray attack causes the dependent service to fail immediately. The correct approach for service accounts differs from user accounts:
Option 1: Disable lockout for service accounts (PSO LockoutThreshold = 0) The tradeoff is that brute-force attacks against the service account credential succeed eventually if the password is weak. Mitigate with high-complexity passwords (30+ characters, managed by a PAM vault) that are immune to practical brute force.
Option 2: Very high lockout threshold (50-100 failures) Allows detection of a brute-force attempt (via Event ID 4625 surge) before lockout occurs. The service continues operating while the attack is detected and the source IP is blocked.
Option 3: Migrate to gMSA (Group Managed Service Account) The definitive solution. gMSAs are managed by AD, rotate their own passwords automatically every 30 days, and are not subject to user password policies at all. Services running as gMSAs cannot be brute-forced because no human or attacker ever knows the password. Deploy gMSA for every service account that supports it:
# Create a gMSA
New-ADServiceAccount -Name "svc-webapp" `
-DNSHostName "svc-webapp.domain.com" `
-PrincipalsAllowedToRetrieveManagedPassword "WebAppServers"
# Install the gMSA on the target server
Install-ADServiceAccount -Identity "svc-webapp"
# Verify installation
Test-ADServiceAccount -Identity "svc-webapp"
The bottom line
Fine-Grained Password Policies give Active Directory administrators the granular control that single-domain-policy environments cannot provide. Deploy separate PSOs for Tier 0 admins (20+ character, strict lockout), service accounts (30+ character, no expiry, no lockout or high threshold), and Tier 1 admins. Apply PSOs to global security groups, not OUs. Use shadow groups to approximate OU-based targeting. Verify every high-privilege account has the correct PSO with Get-ADUserResultantPasswordPolicy, and migrate service accounts to gMSAs wherever the application supports it.
Frequently asked questions
Can PSOs be applied to computer accounts?
No. PSOs apply to user objects and inetOrgPerson objects only. Computer accounts use a separate password management mechanism: Active Directory automatically rotates computer account passwords every 30 days by default (controlled by the 'Domain member: Maximum machine account password age' GPO setting). There is no PSO equivalent for computer accounts.
What happens to a user's password when I apply a PSO with a shorter MaxPasswordAge than the user's current password age?
The user's password does not expire immediately. The PSO's MaxPasswordAge applies from the time it is evaluated. At the next password expiry calculation, AD uses the PSO's MaxPasswordAge relative to the date the password was last set. If the password was last set 200 days ago and the PSO requires MaxPasswordAge of 180 days, the password is immediately expired and the user will be prompted to change it at next logon.
How do I audit which PSOs exist in the domain and what they are configured with?
Run: `Get-ADFineGrainedPasswordPolicy -Filter * | Select-Object Name, Precedence, MinPasswordLength, MaxPasswordAge, LockoutThreshold, PasswordHistoryCount | Sort-Object Precedence | Format-Table -AutoSize`. To also see what subjects (users or groups) each PSO applies to, add: `| ForEach-Object { $_ | Add-Member -NotePropertyName Subjects -NotePropertyValue (Get-ADFineGrainedPasswordPolicySubject -Identity $_.Name | Select-Object -ExpandProperty Name) -PassThru }`. Export this output to a CSV and review it quarterly as part of your AD security review.
Is there a way to require passphrase-style passwords (long, no special characters) via PSO?
Sort of. The PSO ComplexityEnabled setting enforces the standard Windows complexity rules (uppercase, lowercase, digit, special character, cannot contain the username). To allow passphrases without special characters, you must disable ComplexityEnabled and compensate with a higher MinPasswordLength. For example: ComplexityEnabled = False, MinPasswordLength = 20 allows a 20-character passphrase of lowercase words without special characters. For users who prefer passphrases, this is a usability improvement while maintaining equivalent entropy.
Can fine-grained password policies be used to block common passwords like 'Password1!'?
Not directly. Fine-grained password policies control length, complexity, history, and lockout thresholds, but they do not check against a list of known-bad passwords. To block common passwords at the AD level, use Microsoft Entra Password Protection, which can be deployed on-premises to DC agents. It checks new passwords against the Microsoft global banned password list (which includes common passwords and their variations) plus a custom list you define. The DC agent intercepts password change requests and rejects those that match banned patterns, regardless of whether they meet standard complexity rules.
How do I apply different PSOs to different user populations in Active Directory?
Fine-grained password policies are applied to users by linking a Password Settings Object (PSO) to a global security group or directly to a user object (not to an OU). Create a global security group for each population requiring a distinct policy (e.g., 'SG-PSO-ServiceAccounts', 'SG-PSO-Executives', 'SG-PSO-StandardUsers'), then link the corresponding PSO to each group. When a user is a member of multiple groups with different PSOs, the PSO with the lowest Precedence number wins. To view the effective PSO for a user: Get-ADUserResultantPasswordPolicy -Identity username. If no PSO applies, the user falls back to the Default Domain Policy. Service accounts that cannot tolerate password changes (legacy apps) should have a dedicated PSO with a long maximum password age and be migrated to gMSA as soon as feasible.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
