Tutorials › PowerShell
Find and fix 'password never expires' accounts with PowerShell
"Password never expires" is often ticked to make a problem go away and then forgotten. On an admin account it means one leaked password could work for years. This tutorial uses PowerShell to find these accounts, check them, and switch the setting off safely, with a dry run first.
Before you start
- You need an account that can modify users in Active Directory, and the Active Directory module for PowerShell. It is installed on domain controllers, and on other machines with the RSAT Active Directory tools.
- Agree with the account owners what should happen. Some service accounts have this ticked on purpose, and changing them without a plan can stop an application.
- Have a list of your break-glass and service accounts to hand.
Steps
- Sign in to a domain controller or a management server with RSAT installed.
- Right-click Start and select Terminal (Admin) or Windows PowerShell (Admin).
- Load the module:
Import-Module ActiveDirectory - Check your domain's maximum password age. You'll need it in step 9:
Get-ADDefaultDomainPasswordPolicy | Select-Object MaxPasswordAge - List every enabled user with the setting turned on, oldest password first:
Get-ADUser -Filter 'PasswordNeverExpires -eq $true -and Enabled -eq $true' -Properties PasswordNeverExpires, PasswordLastSet, LastLogonDate | Select-Object Name, SamAccountName, PasswordLastSet, LastLogonDate, DistinguishedName | Sort-Object PasswordLastSet - Look at privileged accounts first. Accounts with
AdminCountset to 1 are, or have been, in a protected admin group. Microsoft's own example uses this filter:
A human admin account in this list is the thing to fix first.Get-ADUser -Filter {(AdminCount -eq 1) -and (PasswordNeverExpires -eq $true)} | Select-Object Name, SamAccountName - Export the full list so you have a record and can get sign-off:
CreateGet-ADUser -Filter 'PasswordNeverExpires -eq $true -and Enabled -eq $true' -Properties PasswordNeverExpires, PasswordLastSet, LastLogonDate, AdminCount | Select-Object Name, SamAccountName, PasswordLastSet, LastLogonDate, AdminCount, DistinguishedName | Export-Csv C:\Temp\password-never-expires.csv -NoTypeInformationC:\Tempfirst if it doesn't exist. - Open the CSV in Excel. Remove every service account, break-glass account and anything you don't recognise. Save what's left as
C:\Temp\to-fix.csv, keeping theSamAccountNamecolumn. - Compare each
PasswordLastSetdate with the maximum password age from step 4. If a password is older than that, the user will have to change it as soon as the flag is removed. Tell those users first, and check they're in the office or can reach self-service password reset.Removing the flag from an account with an old password can lock a user, or an application using that account, out straight away. Never run step 11 against service accounts without the application owner on board. - Do a dry run.
-WhatIfshows what would change without changing anything:
Read the output and check every name is one you expect.Import-Csv C:\Temp\to-fix.csv | ForEach-Object { Set-ADUser -Identity $_.SamAccountName -PasswordNeverExpires $false -WhatIf } - When you're happy, run it for real by removing
-WhatIf:Import-Csv C:\Temp\to-fix.csv | ForEach-Object { Set-ADUser -Identity $_.SamAccountName -PasswordNeverExpires $false } - To limit a change to one OU instead of using a CSV, use
-SearchBase, as in Microsoft's Q&A example. It includes OUs nested underneath:Get-ADUser -Filter 'PasswordNeverExpires -eq $true' -SearchBase "OU=Staff,DC=contoso,DC=local" | Set-ADUser -PasswordNeverExpires $false -WhatIf
Check it worked
- Run the search again for the accounts you changed. It should return nothing:
Every line should showImport-Csv C:\Temp\to-fix.csv | ForEach-Object { Get-ADUser -Identity $_.SamAccountName -Properties PasswordNeverExpires | Select-Object SamAccountName, PasswordNeverExpires }False. - In Active Directory Users and Computers, open one of the users, go to the Account tab and check Password never expires is no longer ticked.
- Keep the CSV from step 7 with your change notes so you can show what was changed and when.
For service accounts that can't have expiring passwords, look at moving them to group managed service accounts (gMSA) over time. Windows changes those passwords for you.
Sources
- Microsoft Learn (archive): Security focus: AD privileged users whose passwords don't expire
- Microsoft Q&A: PowerShell Active Directory password never expires