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 sent to the E-mail address set on their AD account. If the user’s “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 accounts 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 or to more easily install the RSAT tools via PowerShell Install all RSAT tools via PowerShell
- 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 “[email protected]” 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 [email protected] 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 = "[email protected]"
$SMTPServer = "smtp.office365.com"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "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 = "[email protected]"
$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 = "[email protected]"
$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)
}
Hi Phil, From your above code i am trying to configure password expiry email notification for one particular domain account. So from your code i have commented the “$ADUsers =” line added $ADUsers = Get-ADUser -Identity USERNAME -Properties “msDS-UserPasswordExpiryTimeComputed”,mail -searchbase “OU=Users,OU=Specops,DC=specopsdemo1,DC=com” –Server company.specopsdemo1.com. However it is failing with below error. Please help me to fix this error.
+ … ireDate_String. But can’t email them as their AD mail feild is balnk”
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The string is missing the terminator: ‘.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
Hello Phil,
Thanks for putting this script together, it appears to be exactly what I was looking for. However, I am getting an error related to the FromFileTime calculation.
Exception calling “FromFileTime” with “1” argument(s): “Not a valid Win32 FileTime.
Parameter name: fileTime”
At C:\PwdEmailScript\PwdExpEmail.ps1:20 char:5
+ $ExpireDate = [datetime]::FromFileTime( $User.’msDS-UserPasswordE …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
– Any thoughts on what I may be doing wrong here or why this is occurring?
I also slightly modified the Get-ADUSer line to try and remove users with null value passwords.
$ADUsers = Get-ADUser -Filter {Enabled -eq $true -and PasswordNeverExpires -eq $false -and PasswordLastSet -gt 0} -Properties ‘msDS-UserPasswordExpiryTimeComputed’, ‘mail’
$AlreadyExpiredList = “”
Love it! Thank you!!!! Works fine 🙂
Glad it helped.
Phil
Hi! Please tell me what to add and where to add it. In order to make this script work ONLY for a specific OU ?
Great code, thanks!
Just a comment, review the condition ” if($null -eq $user.mail)”, the email will never be sent.