How-to: PowerShell script to send a password expiry reminder email

When connected to the domain with a Windows computer, you will normally be warned at logon if your password is about to expire. A remotly connected (VPN/Citrix) user may never see this warning, this can lead to unexpected password expiries that waste the time of both remote workers and IT helpdesk staff.

The script below can be run to send an HTML formatted email alert to users before their password expires. If the script is scheduled to run once per day, users whose password is due to expire in less than 5 days will get a daily reminder email.

In 2019 Microsoft dropped the GPO baseline password-expiration policies that require periodic password changes, as they had proven counter productive in improving security.

Change the values in bold to match your environment.

# New-PasswordReminder.ps1

###################################
# Get the max Password age from AD 
###################################
function Get-maxPwdAge {
   $root = [ADSI]"LDAP://SS64domain"
   $filter = "(&(objectcategory=domainDNS)(distinguishedName=DC=example,DC=com))"
   $ds = New-Object system.DirectoryServices.DirectorySearcher($root,$filter)
   $dc = $ds.findone()
   [int64]$maxpwdage = [System.Math]::Abs( $dc.properties.item("maxPwdAge")[0])
   $maxpwdage/864000000000
}

###################################
# Function to send HTML email to each user
###################################

function send_email ($days_remaining, $email, $name ) {
   $today = Get-Date
   $today = $today.ToString("dddd (yyy-MMMM-dd)")
   $date_expire = [DateTime]::Now.AddDays($days_remaining);
   $date_expire = $date_expire.ToString("dddd (yyy-MMMM-dd)")
   $SmtpClient = new-object system.net.mail.smtpClient 
   $mailmessage = New-Object system.net.mail.mailmessage 
   $SmtpClient.Host = "MAIL64.example.com" 
   $mailmessage.from = "IT Helpdesk <your_email@example.com>" 
   $mailmessage.To.add($email)
   $mailmessage.Subject = "$name, Your password will expire soon."
   $mailmessage.IsBodyHtml = $true

   $mailmessage.Body = @"
<h5><font face=Arial>Dear $name, </font></h5>
<h5><font face=Arial>Your password will expire in <font color=red><strong>$days_remaining</strong></font> days
 on <strong>$date_expire</strong><br /><br />
Your domain password is required for Computer Login, remote VPN, and Email Access.<br /<br />
To change your password, press CTRL-ALT-DEL and choose Change Password.<br /><br />
For your password to be valid it must be 8 or more characters long and<br />
contain a mix of THREE of the following FOUR properties:<br /><br />
    uppercase letters (A-Z)<br />
    lowercase letters (a-z)<br />
    numbers (0-9)<br />
    symbols (!"£$%^&*)<br /><br />
If you have any questions, please contact the IT Helpdesk on 0000 000 000 <br /><br />
 Generated on : $today<br /><br />
_____________ <br />
<br /></font></h5>
"@

   $smtpclient.Send($mailmessage) 
}

###################################
# Search for Non-disabled AD users that have a Password Expiry.
###################################

$strFilter = "(&(objectCategory=User)(logonCount>=0)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(userAccountControl:1.2.840.113556.1.4.803:=65536)))"

$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$colResults = $objSearcher.FindAll();

# how many days before PW expiry do we start sending reminder emails?
$max_alert = 5


# Get the maximum password lifetime
$max_pwd_life=Get-maxPwdAge

$userlist = @()
ForEach ($objResult in $colResults) {
   $objItem = $objResult.Properties; 
   if ( $objItem.mail.gettype.IsInstance -eq $True) {      
      $user_name = $objItem.name
      $user_email = $objItem.email
      #Transform the DateTime readable format
      $user_logon = [datetime]::FromFileTime($objItem.lastlogon[0])
      $result = $objItem.pwdlastset 
      $user_pwd_last_set = [datetime]::FromFileTime($result[0])

      #calculate the difference in Day from last time a password was set
      $diff_date = [INT]([DateTime]::Now - $user_pwd_last_set).TotalDays;

      $Subtracted = $max_pwd_life - $diff_date
      if (($Subtracted) -le $max_alert) {
         $selected_user = New-Object psobject
         #$selected_user | Add-Member NoteProperty -Name "Name" -Value $objItem.name[0]
         $selected_user | Add-Member NoteProperty -Name "Name" -Value $objItem.Item("displayname")
         $selected_user | Add-Member NoteProperty -Name "Email" -Value $objItem.mail[0]
         $selected_user | Add-Member NoteProperty -Name "LastLogon" -Value $user_logon
         $selected_user | Add-Member NoteProperty -Name "LastPwdSet" -Value $user_pwd_last_set
         $selected_user | Add-Member NoteProperty -Name "RemainingDays" -Value ($Subtracted)
         $userlist+=$selected_user
      }
   }
}
   
###################################
# Send email to each user
###################################
   ForEach ($userItem in $userlist ) {
      If ($userItem.RemainingDays -ge 0) {
         send_email $userItem.RemainingDays $userItem.Email $userItem.Name
         # send_email $userItem.RemainingDays testing@example.com $userItem.Name
      }
   }

# END

For instructions of how to download and run this script see: Run a PowerShell script.

Based on a script by Levente Veres
This script assumes that you have not used Fine Grained Password policies, to override the Default Domain Policy.

The default windows domain logon password reminder is 14 days, if you are also sending reminders by email, you may wish to reduce the logon reminder to 5 days or so, this can be configured in the Default Domain Group Policy under Interactive logon: Prompt user to change password before expiration.

“I've seen things you people wouldn’t believe. Attack ships on fire off the shoulder of Orion. I watched c-beams glitter in the dark near the Tannhäuser Gate. All those moments will be lost in time, like tears in rain“ ~ Bladerunner

Related PowerShell Cmdlets

ucunleashed.com - PW expiry reminder that will handle Fine Grained password policies (PowerShell).
Find out when your Password Expires - AD PowerShell blog - includes Fine Grained Password Policies.
Sheen austin - AD Password Expiry Reminder Email (VBScript).
Thelowedown - AD Automated password expiration warnings (Perl).


 
Copyright © 1999-2024 SS64.com
Some rights reserved