Understanding Windows Domain Password Expiration: Behavior, Enforcement, and Technical Implications


2 views

In Active Directory environments, password expiration (configured via MaximumPasswordAge in Group Policy) doesn't immediately lock accounts. Instead, it triggers a password change requirement at next login after expiration. Here's the exact workflow:


# Check password expiration for a user
Get-ADUser -Identity username -Properties PasswordLastSet, PasswordNeverExpires |
Select-Object Name, 
    @{Name="PasswordLastSet";Expression={$_.PasswordLastSet}},
    @{Name="PasswordExpires";Expression={
        if ($_.PasswordNeverExpires) { "Never" }
        else { $_.PasswordLastSet.AddDays((Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge) }
    }}

Windows provides a PasswordGracePeriod (default 0 days) during which users can still log in with expired passwords but must change them immediately:

  • Day 0-90 (default max age): Normal login
  • Day 91: Password "expires"
  • Day 91-94 (with grace period): Can login but forced to change
  • Day 95+: Account locked (if grace period exceeded)

The actual enforcement happens through the LOGON32_LOGON_NETWORK and LOGON32_LOGON_INTERACTIVE types:


// Simplified authentication flow
if (UserPasswordExpired) {
    if (LogonType == INTERACTIVE) {
        return STATUS_PASSWORD_MUST_CHANGE;
    } else {
        return STATUS_PASSWORD_EXPIRED; // Blocks non-interactive logins
    }
}

When building applications that integrate with AD:

  1. Service accounts should have non-expiring passwords
  2. Handle ERROR_PASSWORD_EXPIRED (1330) in your code
  3. For scheduled tasks, use Task Scheduler with stored credentials

# Create scheduled task with stored credentials
$action = New-ScheduledTaskAction -Execute "YourApp.exe"
$trigger = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -DontStopOnIdleEnd -StartWhenAvailable
Register-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -TaskName "MyApp" -User "DOMAIN\svc_account" -Password "p@ssw0rd"

Modern security recommendations suggest:

Traditional Approach Modern Approach
90-day expiration Disable expiration + MFA
Complexity requirements Passphrases + banned password lists
Account lockout after 3 attempts Smart lockout with IP awareness

To implement modern policies:


# Set fine-grained password policy
New-ADFineGrainedPasswordPolicy -Name "NoExpirationPolicy" 
    -Precedence 100 
    -MaxPasswordAge "0" 
    -MinPasswordLength 12 
    -ComplexityEnabled $true 
    -ReversibleEncryptionEnabled $false 
    -AppliesTo "CN=Developers,OU=Groups,DC=domain,DC=com"

In Windows Active Directory environments, password expiration (set via the MaximumPasswordAge attribute) doesn't immediately lock accounts or prevent login attempts after the expiration date. The actual enforcement occurs during the authentication process with this sequence:

# PowerShell to check password expiration
Get-ADUser -Identity username -Properties PasswordLastSet, PasswordNeverExpires |
Select-Object Name, 
    @{Name="PasswordAge";Expression={(Get-Date) - $_.PasswordLastSet}},
    @{Name="MaxPasswordAge";Expression={(Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge}}

The authentication workflow handles password expiration through these steps:

  1. System checks if current date > (PasswordLastSet + MaxPasswordAge)
  2. If expired, the Netlogon service forces password change during next interactive login
  3. The "User must change password at next logon" flag gets set automatically

Microsoft implemented this behavior for practical administration reasons:

  • Allows grace period for mobile/offline users
  • Prevents sudden service interruptions
  • Maintains Kerberos ticket validity until next renewal

Additional controls exist for stricter enforcement:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters]
"DisablePasswordChange"=dword:00000000
"MaximumPasswordAge"=dword:0000001e

Key Group Policy settings:

  • Interactive logon: Prompt user to change password before expiration (sets warning period)
  • Network security: Force logoff when logon hours expire (can be applied similarly)

When building authentication systems that integrate with AD:

// C# example checking password status
using System.DirectoryServices;

public bool IsPasswordExpired(string username)
{
    DirectoryEntry user = new DirectoryEntry($"LDAP://{username}");
    PropertyCollection props = user.Properties;
    
    DateTime lastSet = (DateTime)props["pwdLastSet"].Value;
    TimeSpan maxAge = TimeSpan.FromDays((int)props["maxPwdAge"].Value / -864000000000);
    
    return (DateTime.Now - lastSet) > maxAge;
}

While the grace period exists, these measures help maintain security:

  • Kerberos tickets become invalid after password change
  • Existing sessions typically aren't terminated (design limitation)
  • Smart card authentication behaves differently (immediate enforcement)