I recently put together the following PowerShell script to email users that their On-Premise Active Directory password is due to expire soon. I have this script running via a scheduled task once a day (powershell -file C:\scroipts\PasswordNotifer.ps1).

The script will email all enabled user accounts that are not set to “Password never expires”. E-mails are send to the E-mail address set on their AD account. If the users “mail” attribute is empty an email is instead is sent to another address specified in the script such as an IT Department. Finally another email is sent to the IT Department (or another other address you specify) containing a list of account which have already expired.

The script includes the number of days remaining in the subject and an HTML body containing whatever guidance you need to give your users.

Prerequisites

  • To be able to import the “ActiveDirectory” PowerShell module you will need to run the script on a computer with RSAT Remote Server Administration Tools installed.  Download RSAT for Windows 10
  • The script will need to run run by a domain user in the domain your are querying. A standard AD user is fine the script does not need any admin rights over AD.
  • The script is currently emailing via an Office 365 Mail account. You will need a licensed account to send the emails. If you want to send the email via another method just update the SMTP server and other details as required.
  • You users will need a valid  email address in their AD mail attribute.

What to change

  • Line 4 $warnDays – How many days before expiry to start emailing the users form.
  • Line 7 $EmailFrom  – The from address for the emails sent to users. The email account you specify in $SMTPClient.Credentials will need  permissions to send from this address.
  • Line 11 $SMTPClient.Credentials – Replace “O365User@domain.com” and “Password” with the credentials for the email account you are using to sent emails
  • Line 21 – If required change the Date Time format “dd/MM/yyyy h:mm tt”. Currently UK format. Standard date and time format strings
  • Line 35 & 37 – If required change the wording for the email subject
  • Line 44 – Change ITDept@domain.com to the email address you would like to notify if the users AD mail attribute is empty. Line 45 for the message to send that address
  • Line 51 to 65 – The HTML email body to send your users
  • Line 82 & 83 – The email address and subject to notify of users who’s passwords have already expired.

The Script

Import-Module ActiveDirectory

$Today = Get-Date
$warnDays = 14 # How many days remaining to email from

# Email setup
$EmailFrom = "O365User@domain.com"
$SMTPServer = "smtp.office365.com" 
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587) 
$SMTPClient.EnableSsl = $true 
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("O365User@domain.com", "Password"); 

# Get a list of AD accounts where enables and the password can expire
$ADUsers = Get-ADUser -Filter {Enabled -eq $true  -and PasswordNeverExpires -eq $false } -Properties 'msDS-UserPasswordExpiryTimeComputed', 'mail'
$AlreadyExpiredList = ""

# For each account
$Results = foreach( $User in $ADUsers ){
    # Get the expiry date and convert to date time
    $ExpireDate = [datetime]::FromFileTime( $User.'msDS-UserPasswordExpiryTimeComputed' )
    $ExpireDate_String = $ExpireDate.ToString("dd/MM/yyyy h:mm tt") # Format as UK

    # Calculate the days remaining
    $daysRmmaining  = New-TimeSpan -Start $Today -End $ExpireDate
    $daysRmmaining = $daysRmmaining.Days

    $usersName = $User.Name

    # Email users with a remaining count less than or equal $warnDays but also 0 or greater (no expired yet)
    if ($daysRmmaining -le $warnDays -And $daysRmmaining -ge 0)
    {
        # Generate email subjet from days remaining
        if ($daysRmmaining -eq 0)
        {
            $emailSubject = "Your password expires today"
        } else {
            $emailSubject = "Your password expires in $daysRmmaining days"
        }

        # Get users email
        if($null -eq $user.mail)
        {
            # The user does not have an email address in AD, alert the IT department
            $sendTo = "ITDept@domain.com"
            $emailBody = "$usersName password expires $ExpireDate_String. But can't email them as their AD mail feild is balnk :-("
        } else {
            # The user has an email address
            $sendTo = $user.mail

            $emailBody = "
                $usersName,</br></br>
                Your password expires $ExpireDate_String.</br></br>

                It is important that you reset your password ASAP to avoid any disruption.</br></br>
                
                How do I reset my password.</br>
                1. If you are not at the Head Office connect to the VPN.</br>
                2. While logged on press CTRL + ALT + DELETE and click Change Password.</br>
                3. Enter your current password, enter and confirm a new password that meets the below password policy. Press Enter</br>
                4. Press CTRL + ALT + DELETE and click Lock.</br>
                5. Unlock your computer with your new password</br></br>
                
                Thank you for your co-operation.</br></br>
                
                IT Dept</br>
            "

           $SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$sendTo,$emailSubject,$emailBody)
           $SMTPMessage.IsBodyHTML = $true
           $SMTPClient.Send($SMTPMessage)
        }
    } elseif ($daysRmmaining -lt 0) {
        # Password already expired, add the users details to a list ready for email
        $userMail = $user.mail
        $AlreadyExpiredList = $AlreadyExpiredList + "$usersName, $userMail, $ExpireDate_String</br>"
    }    
}

# Send already expired, alert the IT department with the list of people
if ($null -ne $AlreadyExpiredList)
{
    $sendToAlreadyExpired = "ITDept@domain.com"
    $subjectAlreadyExpired = "These users passwords have expired. They may need assistance"

    $SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom,$sendToAlreadyExpired,$subjectAlreadyExpired,$AlreadyExpiredList)
    $SMTPMessage.IsBodyHTML = $true
    $SMTPClient.Send($SMTPMessage)
}