Skip to main content
Active DirectoryGroup PoliciesPowershell

Password Change Notification When an AD User Password is About to Expire

By June 2, 2021January 16th, 2022No Comments

In this post we’ll show how to find out when a password of an Active Directory user account expires using PowerShell, how to set a password to never expire (PasswordNeverExpires = True), and notify users in advance to change their password.

If a user password in a domain has expired their password, the account is not locked, but it cannot be used to access domain resources until the user changes the expired password to a new one. Most often remote users come across problems with expired passwords, since they cannot change their passwords using standard tools.

A user password expiry time limit in a domain, how often it must be changed (maximum password age) and complexity requirements are set in the AD domain password policy. These parameters are usually set in the Default Domain Policy or the Fine-Grained Password Policy.

You can get the current password expiration policy settings in a domain using this PowerShell command:

Get-ADDefaultDomainPasswordPolicy|select MaxPasswordAge

In our example, the maximum user password age in the domain is 60 days.

powershell: Get-ADDefaultDomainPasswordPolicy|select MaxPasswordAge

How to Get a User Password Expiration Date in Active Directory?

You can view the password age and the date when it was changed last time in the command prompt using the Net user command:

net user jsmith /domain

net user domain - get password last set and expiration date values

You can find the information you need in these lines:

  • Password last set — 9/9/2020 9:23:59 AM
  • Password expires — 1/7/2021 9:23:59 AM
  • Password changeable — 9/10/2020 9:23:59 AM

You can get the password expiration date for any user. To do this, you don’t need administrator privileges or delegated privileges on the AD container with user accounts.

To view the settings of AD accounts, we will use a special PowerShell for Active Directory module that allows you to get values of different AD object attributes (see how to install and import the AD PowerShell module in Windows 10 and Windows Server 2012 R2/2016).

Using the Get-ADUser cmdlet, you can view the date when the user’s password was changed last time and check if the PasswordNeverExpires option is set:

get-aduser jsmith -properties PasswordLastSet, PasswordNeverExpires, PasswordExpired |ft Name, PasswordLastSet, PasswordNeverExpires,PasswordExpired

powershell: get-aduser PasswordLastSet, PasswordNeverExpires,PasswordExpired
  • PasswordLastSet is the date and time of the last password change;
  • PasswordNeverExpires returns True if a user password is never expires;
  • PasswordExpired – if a user password has expired, it returns True, if the password is not expired, it returns False.

You can check the time of the last password change in the graphical MMC snap-in Active Directory Users & Computers (dsa.msc). To do it, open user properties, go to the Attribute Editor tab and check the value of the pwdLastSet attribute.

But as you can see, the MMC snap-in only shows the time when the password was changed. It is not clear when the password expires.

pwdlastset value in user properties ADUC

To get the password expiry date instead of the time it was last changed, use a special constructed AD attribute: msDS-UserPasswordExpiryTimeComputed. The msDS-UserPasswordExpiryTimeComputed value is calculated automatically based on the date of the last password change and the domain password policy.

The UserPasswordExpiryTimeComputed parameter returns the date in the TimeStamp format, so I use the FromFileTime function to convert it to human readable value:

Get-ADUser -Identity jsmith -Properties msDS-UserPasswordExpiryTimeComputed | select-object @{Name="ExpirationDate";Expression= {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed") }}

Thus, we got a user password expiration date.

Get-ADUser msDS-UserPasswordExpiryTimeComputed

If the value of msDS-UserPasswordExpiryTimeComputed is 0, it means that pwdLastSet is empty (null) or equals to 0 (the password has never been changed).

To get password expiry dates for all users from the specific container (OU) in AD, you can use the following PowerShell script:

$Users = Get-ADUser -SearchBase 'OU=Users,OU=NewYork,DC=contoso,DC=com' -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet, CannotChangePassword
$Users | select Name, @{Name="ExpirationDate";Expression= {[datetime]::FromFileTime ($_."msDS-UserPasswordExpiryTimeComputed")}}, PasswordLastSet

It results in a table with the list of active users, expiration date and time of the last password change.

How to Get AD Users Password Expiration Date using powershell

You can display only the list of users with expired passwords:

$Users = Get-ADUser -SearchBase 'OU=Users,OU=NewYork,DC=contoso,DC=com' -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet, CannotChangePassword
foreach($user in $Users){
if( [datetime]::FromFileTime($user."msDS-UserPasswordExpiryTimeComputed") -lt (Get-Date)) {
$user.Name
}
}

How to Set AD User Password to Never Expire

If you want to set a permanent password for an account, check the Password Never Expires option in the user properties in AD.

ADUC: user's option "Password never expires"

Or you can enable this option with PowerShell by setting the user attribute:

Get-ADUser jsmith | Set-ADUser -PasswordNeverExpires:$True

You can set the Password Never Expires option at once for multiple users from a list in a text file:

$users=Get-Content "C:\PS\users_password_never_expire.txt"
Foreach ($user in $users) {
Set-ADUser $user -PasswordNeverExpires:$True
}

You can display the list of all users with the disabled regular password change option:

Get-ADUser -filter * -properties Name, PasswordNeverExpires | where {$_.passwordNeverExpires -eq "true" } |  Select-Object DistinguishedName,Name,Enabled |ft

Active Directory Password Expiration Notification Policy

Windows has a special Group Policy parameter that allows to notify users that they must change their passwords.

The policy is called Interactive logon: Prompt user to change password before expiration and is located under the GPO section: Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Local Policies -> Security Options.

By default, the policy is enabled on the local Windows settings, and the notifications start to appear 5 days before a password expires. You can change the number of days that users will see a password change notification.

Group Policy parameter: Interactive logon: Prompt user to change password before expiration

After enabling this policy, if the user’s password expires, a notification to change a password will appear in the tray each time a user logs on.

Consider changing your password
Your password will expire in xx days.
Consider changing your password notification in Windows 10

You can also use a simple PowerShell script that automatically shows a dialog window with the prompt to change a password if it expires in less than 5 days:

Add-Type -AssemblyName PresentationFramework
$curruser= Get-ADUser -Identity $env:username -Properties 'msDS-UserPasswordExpiryTimeComputed','PasswordNeverExpires'
if ( -not $curruser.'PasswordNeverExpires') {
$timediff=(new-timespan -start (get-date) -end ([datetime]::FromFileTime($curruser."msDS-UserPasswordExpiryTimeComputed"))).Days
if ($timediff -lt 5) {
$msgBoxInput = [System.Windows.MessageBox]::Show("Your password expires in "+ $timediff + " days!`nDo you want to change it now?","Important!","YesNo","Warning")
switch ($msgBoxInput) {
'Yes' {
cmd /c "explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}"
}
'No' { }
}
}
}

If a user clicks YES, a Windows Security window appears that you see after pressing Ctrl+Alt+Del or Ctrl+Alt+End (in case of an RDP/RDS connection).

password expiration reminder using PowerShell

The script implies that the PowerShell for AD module is installed on users’ computers. It can be used even if RSAT is not installed. Check the article “Deploy PowerShell Active Directory Module Without Installing RSAT”.

Enable automatic startup for the PS script or run it as a GPO logon script.

Password Expiration Email Notification via Powershell

If you want to notify users about their password expiry by email, you can use this PowerShell script:

$Sender = "[email protected]"
$Subject = 'Important! Your password expires soon!'
$BodyTxt1 = 'Your password for'
$BodyTxt2 = 'expires in '
$BodyTxt3 = 'days. Remember to change your password in advance. If you have other questions, contact the HelpDesk.'
$smtpserver ="smtp.contoso.com"
$warnDays = (get-date).adddays(7)
$2Day = get-date
$Users = Get-ADUser -SearchBase 'OU=Users,OU=NewYork,DC=contoso,DC=com' -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, EmailAddress, Name | select Name, @{Name ="ExpirationDate";Expression= {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}, EmailAddress
foreach ($user in $users) {
if (($user.ExpirationDate -lt $warnDays) -and ($2Day -lt $user.ExpirationDate) ) {
$lastdays = ( $user.ExpirationDate -$2Day).days
$EmailBody = $BodyTxt1, $user.name, $BodyTxt2, $lastdays, $BodyTxt3 -join ' '
Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $smtpserver -Subject $Subject -Body $EmailBody
}
}

The script checks all active domain users whose passwords are about to expire. In 7 days before the password expires, a user starts to get emails sent to the address specified in AD. Emails are sent until the password is changed or expires. An administrator can force the user password change using the Set-ADAccountPassword cmdlet.

Run this PowerShell script regularly on any computer/server in your domain (it is easier to do it with the Task Scheduler). Of course, you will have to add the IP address of the host that is sending emails to the allowed senders list (can send email without authentication) on your SMTP server.

Leave a Reply