Notify Users for Password Expiration
Scenario:
Notify Users for Password Expiration
The script that we will discuss below is about notifying domain users via email when the password will expire. Based on the policy of each company, you set the rules in Group Policy for the password to expire on the specified time. When the expiration date is close you can configure the Group Policy to notify the users that the password will expire and that need to take action to change there password. This notification on the right bottom side of the screen can sometimes be skipped or if the user is outside of the domain network will not receive the notification.
The below script provides another way of informing the user that the password will expire soon, in several emails, in order for the user to change the password.
General Information
In general the script will collect all users with the password expiry date and check if the password expiry date is close. In the script we define when we need to start notifying the user via email. The first notification will start at 30 days prior to the password expiry date. If the password will expire in 30 days then the script will send an email to that user. Te second notification comes at 15 days. If the password of the user will expire in 15 days, the user will receive a second email notification to take action and change the password. If the user will not change the password again, then the script will start sending an email to the user everyday until the password will be changed. This process starts when the password expiration date is 7 days after the current date.
The above process is about informing the affected users when the password expiration date is coming close. In the script, there is another process to inform the it admins when the password of a user has been expired 30 days ago. If there are users in Active Directory that their password has been expired 30 days ago and have not been changed, most probably those users are inactive. So, an email will be sent to the responsible IT to check them out and take action on those account.
Let see now how we are achieving the above in more details.
[adinserter name=”In Article”]
Collecting the information
Firstly in the script we load the Active Directory module that we will need and then we define few variables. The next step is to collect all users and there password expiry date. We will need the below properties of the users:
- Display Name
- Email Address
- extensionAttribute1 (Responsible IT)
- msDS-UserPasswordExpiryTimeComputed (Password Expiry Date)
The extensionAttribute1 is a custom attribute that I am using to set the responsible IT for each user. This attribute is set automatically by another script, that I wrote, based on the Organization Unit that that user is in. You can find the script here. The commands that we need to use to collect that information are below:
Code:
$Users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} –Properties "DisplayName", "EmailAddress", "extensionAttribute1" , "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property "DisplayName", "EmailAddress", "extensionAttribute1", @{Name="PasswordExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}
As you can see above we need to use an expression on msDS-UserPasswordExpiryTimeComputed in order to have the expiry date in a readable format. The format that active Directory keeps the expiry date is a long integer.
[adinserter name=”In Article”]
Script functions
After we have collected all the information that we will need to define our functions that we will call accordingly. As you can see below some functions are called within other functions. The first function (fn_SendEmail
) is the one that will send the email either to the user or the admin. The second function (fn_UserEmail
) is the one that prepares the email that will be sent to the users. This function will be called for all email notifications sent to the users except the final email which is sent at the final day of the expiration. The third function (fn_FinalEmail
) prepares the final email that the script will send to the user. The forth and last function (fn_AdminEmail
) is the one that prepares the email that will be sent to the admins if needed. Below you can see the code related to the function within the script.
Code:
function fn_SendEmail ($To, $Email, $Subject){ $EmailParams = @{ To = $To Subject = $Subject Body = $Email BodyAsHtml = $True Priority = "High" UseSsl = $True Port = "587" SmtpServer = "smtp.office365.com" Credential = $EmailCredentials From = $From} Send-MailMessage @EmailParams } function fn_UserEmail($UserDisplayName, $UserPasswordExpiryDate, $PasswordExpiresInDays, $UserEmailAddress) { $UserEmail = @" <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%3E%0D%0A%0D%0Abody%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20color%3A%23434242%3B%7D%0D%0ATABLE%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bborder-style%3A%20solid%3Bborder-color%3A%20black%3Bborder-collapse%3A%20collapse%3B%7D%0D%0ATR%20%7Bborder-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20%7D%0D%0ATD%20%7Bfont-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20background-color%3A%23C3DDDB%3B%7D%0D%0A.colorm%20%7Bbackground-color%3A%2358A09E%3B%20color%3Awhite%3B%7D%0D%0A.colort%7Bbackground-color%3A%2358A09E%3B%20padding%3A20px%3B%20color%3Awhite%3B%20font-weight%3Abold%3B%7D%0D%0A.colorn%7Bbackground-color%3Atransparent%3B%7D%0D%0A%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<style>" title="<style>" /> <body> <p>Dear $UserDisplayName,</p> <p>Your password will expire in $PasswordExpiresInDays days at $UserPasswordExpiryDate.</p> <p>Please consider changing your password prior to the expiry date/time in order to avoid any loss of access to the systems.</p> <p>Kind regards</p> <p>IT Team</p> </body> "@ $To = $UserEmailAddress $Email = $UserEmail $Subject = "Your password will expire in $PasswordExpiresInDays days." fn_SendEmail $To $Email $Subject } function fn_FinalEmail($UserDisplayName, $UserPasswordExpiryDate, $UserEmailAddress) { $FinalEmail = @" <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%3E%0D%0A%0D%0Abody%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20color%3A%23434242%3B%7D%0D%0ATABLE%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bborder-style%3A%20solid%3Bborder-color%3A%20black%3Bborder-collapse%3A%20collapse%3B%7D%0D%0ATR%20%7Bborder-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20%7D%0D%0ATD%20%7Bfont-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20background-color%3A%23C3DDDB%3B%7D%0D%0A.colorm%20%7Bbackground-color%3A%2358A09E%3B%20color%3Awhite%3B%7D%0D%0A.colort%7Bbackground-color%3A%2358A09E%3B%20padding%3A20px%3B%20color%3Awhite%3B%20font-weight%3Abold%3B%7D%0D%0A.colorn%7Bbackground-color%3Atransparent%3B%7D%0D%0A%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<style>" title="<style>" /> <body> <p>Dear $UserDisplayName,</p> <p>Your password will expire today at $UserPasswordExpiryDate.</p> <p>Please consider changing your password prior to the expiry date/time in order to avoid any loss of access to the systems.</p> <p>Kind regards</p> <p>IT Team</p> </body> "@ $To = $UserEmailAddress $Email = $FinalEmail $Subject = "Your password will expire today" fn_SendEmail $To $Email $Subject } function fn_AdminEmail($AdminEmail, $AdminEmailAddress) { $To = $AdminEmailAddress $Email = $AdminEmail $Subject = "Users with password expired 1 month ago" fn_SendEmail $To $Email $Subject }
[adinserter name=”In Article”]
Processing of users
Now that we have everything ready. We need to process the users and inform the ones needed. In order to do this we are using the below a foreach loop on $Users
variable. In order to check the expiry date and if it is needed to send email to the user we have a switch statement with 3 different cases. The last case prepares our object that includes the users where their password has been expired 30 day ago or more. This object is used later to inform the responsible IT to take action on them.
Code:
foreach ($User in $Users){ $UserPasswordExpiryDate = $User.PasswordExpiryDate $UserDisplayName = $User.DisplayName $UserEmailAddress = $User.EmailAddress $UserResponsibleIT = $User.extensionAttribute1 $PasswordExpiresIn = New-TimeSpan -Start $CurrentDate -End $UserPasswordExpiryDate $PasswordExpiresInDays = $PasswordExpiresIn.Days switch -Regex ($PasswordExpiresInDays){ {($_ -eq $FirstEmailDifference) -or ($_ -eq $SecondEmailDifference) -or (($_ -le $DailyEmailDifference) -and ($_ -gt $NoDiffernce))}{ fn_UserEmail $UserDisplayName $UserPasswordExpiryDate $PasswordExpiresInDays $UserEmailAddress} {$_-eq $NoDiffernce}{ fn_FinalEmail $UserDisplayName $UserPasswordExpiryDate $UserEmailAddress} {$_ -eq $NegativeDifference}{ $ExpiredUser | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value "$UserDisplayName" -Force $ExpiredUser | Add-Member -MemberType NoteProperty -Name "ResponsibleIT" -Value "$UserResponsibleIT" -Force $ExpiredUser | Add-Member -MemberType NoteProperty -Name "PasswordExpiryDate" -Value "$UserPasswordExpiryDate" -Force $ExpiredUsers.Add($ExpiredUser) | Out-Null } } }
[adinserter name=”In Article”]
Informing the Responsible IT
Then we check if our custom object is not empty and if not, we will divide the users within the object into different variables based on the responsible IT. After the users have been divided, the information of the user is user to prepare the list that will be send to the IT admin responsible. The list is in HTML format. When everything is ready there are multiple if statements that check those values and if any of them is not empty, an email will be send with the list to the responsible IT. Below is part of the code that is used for this purpose. At the end of the post you can find the complete script.
Part of Code:
if ($ExpiredUsers -ne ""){ $CyprusUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Cyprus"} $GreeceUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Greece"} $GermanyUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Germany"} $BritishIslesUsers = $ExpiredUsers | Where-Object {($_.ResponsibleIT -eq "Isle of Man") -or ($_.ResponsibleIT -eq "United Kingdom")} $IndiaUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "India"} $PolandUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Poland"} $PhilippinesUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Philippines"} $SingaporeUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Singapore"} $DatacenterUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Datacenter"} $ChinaUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "China"} $HongKongUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Hong Kong"} foreach ($Record in $ExpiredUsers){ $EmailUserDisplayName = $Record.DisplayName $EmailUserPasswordExpiryDate = $Record.PasswordExpiryDate switch -Regex ($Record){ {$CyprusUsers -contains $_}{ $CyprusEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $CyprusEmailResult = $CyprusEmailResult + "`r`n" + $CyprusEmailTemp } {$GreeceUsers -contains $_}{ $GreeceEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $GreeceEmailResult = $GreeceEmailResult + "`r`n" + $GreeceEmailTemp } {$GermanyUsers -contains $_}{ $GermanyEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $GermanyEmailResult = $GermanyEmailResult + "`r`n" + $GermanyEmailTemp }
if ($CyprusEmailResult -ne ""){ $AdminEmailAddress = 'cy-Admin@domain.com' $AdminEmail = $AdminEmailUp+$CyprusEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($GreeceEmailResult -ne ""){ $AdminEmailAddress = 'gr-Admin@domain.com' $AdminEmail = $AdminEmailUp+$GreeceEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject}
Please note that the user that will run the script needs to have access to read User Objects in Active Directory. Also the account needs to have access to the location where the password file is to retrieve the password of the user that will send the email. Please note that the script is configure to user Exchange Online to send the email. If you need to send the email using a different setup then you need to perform changes on the setting configured.
You can download the script here or copy it from below. (Note that code within the script might not be copied correctly due to syntax highlighting.)
Hope you like it.
You feedback is appreciated.
If you have any questions or anything else please let me know in the comments below.
[adinserter name=”In Article”]
Related Links:
- PowerShell Scripts
- PowerShell Tutorials
- Import-Module – Microsoft Docs
- Get-Content – Microsoft Docs
- ConvertTo-SecureString – Microsoft Docs
- New-Object – Microsoft Docs
- Get-ADUser – Microsoft Docs
- Select-Object – Microsoft Docs
- Send-MailMessage – Microsoft Docs
- Get-Date – Microsoft Docs
- New-TimeSpan – Microsoft Docs
- Add-Member – Microsoft Docs
- Out-Null – Microsoft Docs
- Where-Object – Microsoft Docs
- PowerShell Arithmetic Operators
- about_Foreach | Microsoft Docs
- about_Switch | Microsoft Docs
- PowerShell Comparison Operators
[adinserter name=”In Article”]
Solution / Script:
<# .SYNOPSIS Name: Notify-UsersExpiryDate.ps1 The purpose of this script is to notify users when their password is expiring .DESCRIPTION This is a script that it will check everyday the expiry date of users. If the expiry date of the password is after 30 days it will send an email to the user informing him that the password will expire. If the expiry date is after 15 day a second email will be received by the user informing the same. When the expiry date is 7 days or les a daily email will be received by the user until the day of the expiration. At the date of the expiration the script will inform again the user by email that the password will expire. More over the script checks if there are any user accounts in Active Directory that the password has expired 30 days ago and not renewed. Most probably these accounts are inactive. The script will collect those accounts and inform responsible IT to take an action. .RELATED LINKSHome.NOTES Version: 1.0 Release Date: 13-07-2018 Author: Stephanos Constantinou .EXAMPLE Run the script Notify-UsersExpiryDate.ps1 #> Import-Module ActiveDirectory $File = "C:\Scripts\Password.txt" $Key = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32) $EmailUser = "Script-User@domain.com" $Password = Get-Content $File | ConvertTo-SecureString -Key $Key $EmailCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $EmailUser,$Password $To = "" $Email = "" $Subject = "" $From = 'Script-User@domain.com' $CurrentDate = Get-Date $FirstEmailDifference = 30 $SecondEmailDifference = 15 $DailyEmailDifference = 7 $NoDiffernce = 0 $NegativeDifference = -30 $ExpiredUsers = New-Object System.Collections.ArrayList $ExpiredUser = New-Object System.Object $EmailResult = "" $CyprusEmailResult = "" $GreeceEmailResult = "" $GermanyEmailResult = "" $BritishIslesEmailResult = "" $IndiaEmailResult = "" $PolandEmailResult = "" $PhilippinesEmailResult = "" $SingaporeEmailResult = "" $DatacenterEmailResult = "" $ChinaEmailResult = "" $HongKongEmailResult = "" $AdminEmailUp = @" <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%3E%0D%0A%0D%0Abody%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20color%3A%23434242%3B%7D%0D%0ATABLE%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bborder-style%3A%20solid%3Bborder-color%3A%20black%3Bborder-collapse%3A%20collapse%3B%7D%0D%0ATR%20%7Bborder-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20%7D%0D%0ATD%20%7Bfont-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20background-color%3A%23C3DDDB%3B%7D%0D%0A.colorm%20%7Bbackground-color%3A%2358A09E%3B%20color%3Awhite%3B%7D%0D%0A.colort%7Bbackground-color%3A%2358A09E%3B%20padding%3A20px%3B%20color%3Awhite%3B%20font-weight%3Abold%3B%7D%0D%0A.colorn%7Bbackground-color%3Atransparent%3B%7D%0D%0A%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<style>" title="<style>" /> <body> <h3>Below users has been expired 1 month ago</h3> <h4>Below is the list of the users. Please check them:</h4> <table> <tr> <td class="colort">User</td> <td class="colort">Password Expired</td> </tr> "@ $AdminEmailDown = @" </table> </body> "@ $Users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} –Properties "DisplayName", "EmailAddress", "extensionAttribute1" , "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property "DisplayName", "EmailAddress", "extensionAttribute1", @{Name="PasswordExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}} function fn_SendEmail ($To, $Email, $Subject){ $EmailParams = @{ To = $To Subject = $Subject Body = $Email BodyAsHtml = $True Priority = "High" UseSsl = $True Port = "587" SmtpServer = "smtp.office365.com" Credential = $EmailCredentials From = $From} Send-MailMessage @EmailParams } function fn_UserEmail($UserDisplayName, $UserPasswordExpiryDate, $PasswordExpiresInDays, $UserEmailAddress) { $UserEmail = @" <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%3E%0D%0A%0D%0Abody%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20color%3A%23434242%3B%7D%0D%0ATABLE%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bborder-style%3A%20solid%3Bborder-color%3A%20black%3Bborder-collapse%3A%20collapse%3B%7D%0D%0ATR%20%7Bborder-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20%7D%0D%0ATD%20%7Bfont-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20background-color%3A%23C3DDDB%3B%7D%0D%0A.colorm%20%7Bbackground-color%3A%2358A09E%3B%20color%3Awhite%3B%7D%0D%0A.colort%7Bbackground-color%3A%2358A09E%3B%20padding%3A20px%3B%20color%3Awhite%3B%20font-weight%3Abold%3B%7D%0D%0A.colorn%7Bbackground-color%3Atransparent%3B%7D%0D%0A%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<style>" title="<style>" /> <body> <p>Dear $UserDisplayName,</p> <p>Your password will expire in $PasswordExpiresInDays days at $UserPasswordExpiryDate.</p> <p>Please consider changing your password prior to the expiry date/time in order to avoid any loss of access to the systems.</p> <p>Kind regards</p> <p>IT Team</p> </body> "@ $To = $UserEmailAddress $Email = $UserEmail $Subject = "Your password will expire in $PasswordExpiresInDays days." fn_SendEmail $To $Email $Subject } function fn_FinalEmail($UserDisplayName, $UserPasswordExpiryDate, $UserEmailAddress) { $FinalEmail = @" <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%3E%0D%0A%0D%0Abody%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20color%3A%23434242%3B%7D%0D%0ATABLE%20%7B%20font-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bborder-style%3A%20solid%3Bborder-color%3A%20black%3Bborder-collapse%3A%20collapse%3B%7D%0D%0ATR%20%7Bborder-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20%7D%0D%0ATD%20%7Bfont-family%3ASegoe%2C%20%22Segoe%20UI%22%2C%20%22DejaVu%20Sans%22%2C%20%22Trebuchet%20MS%22%2C%20Verdana%2C%20sans-serif%20!important%3B%20border-width%3A%201px%3Bpadding%3A%2010px%3Bborder-style%3A%20solid%3Bborder-color%3A%20white%3B%20background-color%3A%23C3DDDB%3B%7D%0D%0A.colorm%20%7Bbackground-color%3A%2358A09E%3B%20color%3Awhite%3B%7D%0D%0A.colort%7Bbackground-color%3A%2358A09E%3B%20padding%3A20px%3B%20color%3Awhite%3B%20font-weight%3Abold%3B%7D%0D%0A.colorn%7Bbackground-color%3Atransparent%3B%7D%0D%0A%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<style>" title="<style>" /> <body> <p>Dear $UserDisplayName,</p> <p>Your password will expire today at $UserPasswordExpiryDate.</p> <p>Please consider changing your password prior to the expiry date/time in order to avoid any loss of access to the systems.</p> <p>Kind regards</p> <p>IT Team</p> </body> "@ $To = $UserEmailAddress $Email = $FinalEmail $Subject = "Your password will expire today" fn_SendEmail $To $Email $Subject } function fn_AdminEmail($AdminEmail, $AdminEmailAddress) { $To = $AdminEmailAddress $Email = $AdminEmail $Subject = "Users with password expired 1 month ago" fn_SendEmail $To $Email $Subject } foreach ($User in $Users){ $UserPasswordExpiryDate = $User.PasswordExpiryDate $UserDisplayName = $User.DisplayName $UserEmailAddress = $User.EmailAddress $UserResponsibleIT = $User.extensionAttribute1 $PasswordExpiresIn = New-TimeSpan -Start $CurrentDate -End $UserPasswordExpiryDate $PasswordExpiresInDays = $PasswordExpiresIn.Days switch -Regex ($PasswordExpiresInDays){ {($_ -eq $FirstEmailDifference) -or ($_ -eq $SecondEmailDifference) -or (($_ -le $DailyEmailDifference) -and ($_ -gt $NoDiffernce))}{ fn_UserEmail $UserDisplayName $UserPasswordExpiryDate $PasswordExpiresInDays $UserEmailAddress} {$_-eq $NoDiffernce}{ fn_FinalEmail $UserDisplayName $UserPasswordExpiryDate $UserEmailAddress} {$_ -eq $NegativeDifference}{ $ExpiredUser | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value "$UserDisplayName" -Force $ExpiredUser | Add-Member -MemberType NoteProperty -Name "ResponsibleIT" -Value "$UserResponsibleIT" -Force $ExpiredUser | Add-Member -MemberType NoteProperty -Name "PasswordExpiryDate" -Value "$UserPasswordExpiryDate" -Force $ExpiredUsers.Add($ExpiredUser) | Out-Null } } } if ($ExpiredUsers -ne ""){ $CyprusUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Cyprus"} $GreeceUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Greece"} $GermanyUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Germany"} $BritishIslesUsers = $ExpiredUsers | Where-Object {($_.ResponsibleIT -eq "Isle of Man") -or ($_.ResponsibleIT -eq "United Kingdom")} $IndiaUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "India"} $PolandUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Poland"} $PhilippinesUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Philippines"} $SingaporeUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Singapore"} $DatacenterUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Datacenter"} $ChinaUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "China"} $HongKongUsers = $ExpiredUsers | Where-Object {$_.ResponsibleIT -eq "Hong Kong"} foreach ($Record in $ExpiredUsers){ $EmailUserDisplayName = $Record.DisplayName $EmailUserPasswordExpiryDate = $Record.PasswordExpiryDate switch -Regex ($Record){ {$CyprusUsers -contains $_}{ $CyprusEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $CyprusEmailResult = $CyprusEmailResult + "`r`n" + $CyprusEmailTemp } {$GreeceUsers -contains $_}{ $GreeceEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $GreeceEmailResult = $GreeceEmailResult + "`r`n" + $GreeceEmailTemp } {$GermanyUsers -contains $_}{ $GermanyEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $GermanyEmailResult = $GermanyEmailResult + "`r`n" + $GermanyEmailTemp } {$BritishIslesUsers -contains $_}{ $BritishIslesEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $BritishIslesEmailResult = $BritishIslesEmailResult + "`r`n" + $BritishIslesEmailTemp } {$IndiaUsers -contains $_}{ $IndiaEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $IndiaEmailResult = $IndiaEmailResult + "`r`n" + $IndiaEmailTemp } {$PolandUsers -contains $_}{ $PolandEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $PolandEmailResult = $PolandEmailResult + "`r`n" + $PolandEmailTemp } {$PhilippinesUsers -contains $_}{ $PhilippinesEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $PhilippinesEmailResult = $PhilippinesEmailResult + "`r`n" + $PhilippinesEmailTemp } {$SingaporeUsers -contains $_}{ $SingaporeEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $SingaporeEmailResult = $SingaporeEmailResult + "`r`n" + $SingaporeEmailTemp } {$DatacenterUsers -contains $_}{ $DatacenterEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $DatacenterEmailResult = $DatacenterEmailResult + "`r`n" + $DatacenterEmailTemp } {$ChinaUsers -contains $_}{ $ChinaEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $ChinaEmailResult = $ChinaEmailResult + "`r`n" + $ChinaEmailTemp } {$HongKongUsers -contains $_}{ $HongKongEmailTemp = @" <tr> <td class="colorm">$EmailUserDisplayName</td> <td>$EmailUserPasswordExpiryDate</td> </tr> "@ $HongKongEmailResult = $HongKongEmailResult + "`r`n" + $HongKongEmailTemp } } } } if ($CyprusEmailResult -ne ""){ $AdminEmailAddress = 'cy-Admin@domain.com' $AdminEmail = $AdminEmailUp+$CyprusEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($GreeceEmailResult -ne ""){ $AdminEmailAddress = 'gr-Admin@domain.com' $AdminEmail = $AdminEmailUp+$GreeceEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($GermanyEmailResult -ne ""){ $AdminEmailAddress = 'de-Admin@domain.com' $AdminEmail = $AdminEmailUp+$GermanyEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($BritishIslesEmailResult -ne ""){ $AdminEmailAddress = 'bi-Admin@domain.com' $AdminEmail = $AdminEmailUp+$BritishIslesEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($IndiaEmailResult -ne ""){ $AdminEmailAddress = 'in-Admin@domain.com' $AdminEmail = $AdminEmailUp+$IndiaEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($PolandEmailResult -ne ""){ $AdminEmailAddress = 'pl-Admin@domain.com' $AdminEmail = $AdminEmailUp+$PolandEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($PhilippinesEmailResult -ne ""){ $AdminEmailAddress = 'ph-Admin@domain.com' $AdminEmail = $AdminEmailUp+$PhilippinesEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($SingaporeEmailResult -ne ""){ $AdminEmailAddress = 'sg-Admin@domain.com' $AdminEmail = $AdminEmailUp+$SinaporeEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($DatacenterEmailResult -ne ""){ $AdminEmailAddress = 'dc-Admin@domain.com' $AdminEmail = $AdminEmailUp+$DatacenterEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($ChinaEmailResult -ne ""){ $AdminEmailAddress = 'cn-Admin@domain.com' $AdminEmail = $AdminEmailUp+$ChinaEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject} if ($HongKongEmailResult -ne ""){ $AdminEmailAddress = 'hk-Admin@domain.com' $AdminEmail = $AdminEmailUp+$HongKongEmailTemp+$AdminEmailDown fn_AdminEmail $AdminEmail $AdminEmailAddress $AdminSubject}
[adinserter name=”Matched-Content”]


Or you can just ManageEngines free password notifer, A simple effective web interface.
Hello Jeff,
For sure there are several solution that you can do this. This is just one solution along with them.
Thank you
Stephanos
Very Useful Script for every company that use GPO for password expiration.
Hello Kostas,
Thank you for your feedback.
One cool thing I read about is to force the password expired the last day at midnight. This to avoid password being expired in the middle of the day.
Say it expires on 27/07/2018, you force it expired at 00:00 on 27/07/2018
(It might be trickier with world wide companies though)
Hello C-Bam,
This is true. It can be tricky with multi-location companies. In my case I have informed users that the time mentioned in the email is based on the local time of the Datacenter. This is where I scheduled the script to run.
Thanks
Stephanos