In Windows Server Active Directory, every user account is subject to a domain password policy that defines a maximum password age (MaxPwdAge). When the sum of a user's pwdLastSet attribute and the domain's MaxPwdAge falls before the current date, Active Directory considers the password expired and prompts the user to change it at next logon.
The pwdLastSet attribute stores the date and time of the last password change as an Integer8 (64-bit) value in 100-nanosecond intervals since Jan. 1, 1601 UTC. The userAccountControl attribute controls account states including whether an account is disabled (0x2), exempt from password expiration (0x10000), or set so that no password is required (0x20).
For users on a VPN or accessing applications that do not surface password expiration prompts, an expired password can cause an account lockout without warning. Generating a soon-to-expire password report gives IT administrators a list of accounts approaching expiration so that users can be notified before access is disrupted.
Before running the script, make sure the following are in place:
Import the Active Directory module before running the script:
Import-Module ActiveDirectory
There is no single built-in cmdlet that generates a soon-to-expire password report. The script below combines Get-ADDefaultDomainPasswordPolicy to retrieve the domain's maximum password age and Get-ADUser to query user accounts and their PasswordLastSet values. The expiration date is calculated by adding the two together, and accounts falling within the specified window are exported to a CSV file.
Modify $DaysToExpire to match your notification window and update the output path as needed.
Import-Module ActiveDirectory
$DaysToExpire = 14
$Today = Get-Date
$ExpirationThreshold = $Today.AddDays($DaysToExpire)
$DefaultMaxPwdAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
Get-ADUser -Filter { Enabled -eq $True -and PasswordNeverExpires -eq $False } `
-Properties SamAccountName, DisplayName, mail, PasswordLastSet |
Where-Object { $_.PasswordLastSet -ne $null } |
ForEach-Object {
$PasswordExpiresOn = $_.PasswordLastSet + $DefaultMaxPwdAge
[PSCustomObject]@{
SamAccountName = $_.SamAccountName
DisplayName = $_.DisplayName
Mail = $_.mail
PasswordLastSet = $_.PasswordLastSet
PasswordExpiresOn = $PasswordExpiresOn
}
} |
Where-Object {
$_.PasswordExpiresOn -le $ExpirationThreshold -and
$_.PasswordExpiresOn -gt $Today
} |
Export-Csv -Path "C:\Reports\SoonToExpirePasswords.csv" -NoTypeInformation
Note on fine-grained password policies (FGPPs): This script uses the Default Domain Password Policy's MaxPwdAge. If your domain uses FGPPs, specific users or groups may be subject to a different MaxPwdAge from a Password Settings Object (PSO). In that case, use Get-ADUserResultantPasswordPolicy -Identity <SamAccountName> to retrieve the effective policy for each user and apply the correct MaxPasswordAge in the expiration calculation.
| Parameter | Description |
|---|---|
| -Filter | Filters user accounts based on specified attribute conditions; used here to return enabled accounts where PasswordNeverExpires is false. |
| -Properties | Retrieves additional attributes beyond the default set; used here to include SamAccountName, DisplayName, mail, and PasswordLastSet. |
| -SearchBase | Restricts the query to a specific OU or container distinguished name. |
| -Server | Targets a specific domain controller to run the query against. |
| -Credential | Runs the command using alternate credentials. |
| -Path | Specifies the output file path for the CSV report (used with Export-Csv). |
| -NoTypeInformation | Omits the type information header row from the CSV output (used with Export-Csv). |
Active Directory Users and Computers (ADUC) does not include a built-in report or filter for soon-to-expire passwords. Password expiration data is accessible only per user account through the Attribute Editor.
ADUC does not support filtering, sorting, or exporting user accounts based on password expiration proximity. This process must be repeated individually for every account.
ADManager Plus includes a ready-to-use Soon-to-Expire User Passwords report under Password Reports > Password Status Reports. No scripting is required.
To generate the report:
To schedule the report for recurring automated delivery:
The Active Directory module is not installed or not imported. Run Import-Module ActiveDirectory. If the module is unavailable, install RSAT on Windows 10 or 11 via Settings > Optional Features, or add the Active Directory Domain Services role on Windows Server 2016, 2019, or 2022.
The script cannot reach a domain controller. Check network connectivity and DNS resolution, and confirm the Active Directory Web Services (ADWS) service is running on the domain controller using Get-Service -Name ADWS. Use the -Server parameter in Get-ADUser and Get-ADDefaultDomainPasswordPolicy to target a specific domain controller directly.
Run (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge to check the domain's password age. If it returns 00:00:00, passwords never expire at the domain level and no accounts will appear in the report. Also confirm that at least some accounts have PasswordNeverExpires set to False and Enabled set to True, as accounts that do not meet both conditions are excluded by the filter.
The output directory does not exist. Create it first with New-Item -ItemType Directory -Path "C:\Reports" -Force, or update the -Path value in the Export-Csv line to an existing directory.
Confirm that the final Where-Object block contains both conditions: $_.PasswordExpiresOn -le $ExpirationThreshold and $_.PasswordExpiresOn -gt $Today. If the second condition is missing, already-expired accounts will be included. Also verify that $Today is set to Get-Date and not hardcoded to a past date.
The script applies the Default Domain Password Policy's MaxPasswordAge to all accounts. Users under a FGPP with a different MaxPwdAge will produce incorrect expiration dates. Run Get-ADUserResultantPasswordPolicy -Identity <SamAccountName> to check the effective policy for a specific user. If FGPPs are in use, update the script to retrieve and apply the resultant policy per account.
The account running the script lacks read permissions on AD user objects or password policy data. Run PowerShell as an account with at least domain read permissions, or supply alternate credentials using the -Credential parameter in Get-ADUser and Get-ADDefaultDomainPasswordPolicy.
Get-ADUserResultantPasswordPolicy.
ADManager Plus makes AD management easier and faster through a single, intuitive console. Here’s why it’s a better choice for IT teams:
Active Directory calculates password expiration by adding the domain's MaxPwdAge, defined in the Default Domain Password Policy, to the pwdLastSet attribute value for each user account. The pwdLastSet attribute stores the date and time of the last password change as an Integer8 (64-bit) timestamp representing 100-nanosecond intervals since Jan. 1, 1601 UTC. If an FGPP applies to a user or a security group they belong to, the MaxPwdAge from that PSO takes precedence over the domain default.
Get-ADUser and Get-ADDefaultDomainPasswordPolicy are both required. Get-ADDefaultDomainPasswordPolicy retrieves the domain's MaxPasswordAge, and Get-ADUser retrieves user accounts and their PasswordLastSet values. The expiration date is then calculated by adding the two together. There is no single built-in cmdlet that produces a ready-made soon to expire password report; the date arithmetic must be handled within the script.
No. ADUC does not include a report, filtered view, or export feature based on password expiration proximity. The pwdLastSet attribute can be viewed for an individual user through the Attribute Editor after enabling Advanced Features, but there is no mechanism in ADUC to filter or export a domain-wide list of accounts whose passwords are approaching expiration.
A fine-grained password policy (FGPP) is a Password Settings Object (PSO) in Active Directory that allows different password policies to apply to specific users or security groups within the same domain, overriding the Default Domain Password Policy. If a user is subject to an FGPP with a different MaxPwdAge, the expiration calculation must use the FGPP value rather than the domain default. In PowerShell, Get-ADUserResultantPasswordPolicy -Identity <SamAccountName> returns the effective policy for a specific user account. The script on this page uses only the domain default policy and will produce incorrect results for users covered by an FGPP unless modified to include per-user policy lookups.
Yes. ADManager Plus supports multi-domain Active Directory environments. The Select Domain option in the Soon-to-Expire User Passwords report allows administrators to select any domain configured in ADManager Plus. The report can be run independently for each domain from the same console.
ADManager Plus exports the Soon-to-Expire User Passwords report in CSV, PDF, HTML, CSVDE, and XLSX formats, all accessible from the Export As option within the report interface after the report is generated.