Password Expiration Notification Email

One thing that has been missing, likely forever, is a way to notify users of their accounts expiring in email. I find that even though their systems typically prompt them via a sys tray notification or a login screen alert they go ignored. Mac and linux users have problems as well since their systems may not be bound to active directory or prompt with alerts.

I’ve updated my script over the years. Now this version is in powershell. I’ve created it to alert users at set days and then alert their manager if the password hasn’t been changed with one day remaining. This script also sends a summary of expiring users to an email address for review by sys admins or service desk staff.

This will probably be one of the last times I have my code just on this site. I’ll make it easier to grab via Git.



#
# Password Expiration Email to Users
# V.1.1 Gregory Van Den Ham 5 July 2016
#
# History
# V.0.1 - Initial build -10june2016
# V.0.2 - Change logic on expiration notices hours remaining instead of 0 days expired. -26June2016
# V.0.3 - hmtl code formatting admin email table -5July2016
# V.0.4 - debug against test domain controller -5July2016
# V.1.0 - Ready to deploy
# V.1.1 - Fix for expiration in days - showing decimals line 118
##
## UNCOMMENT EMAIL SEND TO FLOW EMAIL :)  Line 163, 227, 369, 398
##
#

Import-Module ActiveDirectory

#
# Variables
#

#Maximum Password Age Set
$maxdays=(Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.TotalDays
#Company Name
$CompanyName = "CompanyName"
#From address for report to Helpdesk/IT Admin staff.
$EmailFromAddress = "ServiceDesk@companyemail.com"
#From address friendly name
$EmailFromName = "CompanyName Corporate IT Service Desk"
#From Phone Number.
$FromPhoneNumber = ""
#Staff Email Address to send email to.
$EmailToAddress = ""
#Staff fullname
$StaffName = ""
#Manager ID
$managerID = ""
#Manager Firstname
$ManagerFirstname = ""
#Manager Address to send email to.
$ManagerEmailToAddress = ""
#Admin Address to send report email to.
$AdminEmailToAddress = "adminemail@companyemail.com"
#Admin Email Subject
$AdminEmailSubject = "Password Expiration Script Results for: " + (Get-Date -Format "ddMMMyyyy")
#Subject for email.
$EmailSubject = ""
#BodyWarning for email.
$EmailBodyWarning = ""
#SMTP Server.
$EmailServer = "emailhostid.mail.protection.outlook.com"
#Admin Email Bod
$scriptexecutetime = Get-Date
$serverrunningscript = $env:computername
$adminsummarybody = ''
$adminsummarybody += ''
$adminsummarybody += ''
$adminsummarybody = "The expiring password script ran at: $scriptexecutetime on: $serverrunningscript 

Summary:
" #Match Filter - Do not report on users in the following OU Container(s) example: {$._UserName -notlike "user1" -and $_.UserName -notlike "*user2"} other verbs, like $SearchOUCriteria = {$_.DistinguishedName -notlike '*OU=Service Accounts,*'} #Sent Email Counters [int]$emailsentcount=0 [int]$manageremailsentcount=0 $ThereAreExpiring=$False #Password Complexity Requirements $PasswordComplexityRequirements= 'Corporate password complexity requires you set a password of at least 8 characters, including three of the four: a Capital letter, a lower case letter, a number, or special character (ex. $, #, @, &, etc). ' # Instructions to reset password if forgotten ## $ForgotPasswordInstructions = 'https://url.sharepoint.com' # Maximum password age notice $MaxPasswordAgeNotice = 'The maximum password age allowed is '+$maxdays+' days.' # Link to password change doc $ChangeInstructionsLink = 'https://url.sharepoint.com' #How to Change Password Instructions $PasswordChangeInstructions= 'If you are in our corporate office using a Windows computer, press Ctrl + Alt + Del and click Change password.
If you are remote using a Windows computer, please connect to the vpn, then press Ctrl + Alt + Del and click Change password.
If you are using a Mac computer follow the instructions at: SharePoint Link to change your password.
' # ## ## End Variables ## Do Not Change Code Beyond this Point ## # # #Function for difference between dates math # function Get-DaysDiff(){ param([datetime]$start, [datetime]$end) $StartDate = Get-Date($start) -Format d $EndDate = Get-Date($end) -Format d $days = (NEW-TIMESPAN -Start $StartDate -End $EndDate).Days return $days } # #Function for Staff Email Send #Variables in: ($EmailToAddress, $EmailSubject, $EmailBodyWarning, $daystoexpire, $expires, $firstname) # function ProcessEmail(){ param([string]$EmailToAddress, [string]$EmailSubject, [string]$EmailBodyWarning, [Double]$daystoexpire, [string]$expires, [string]$firstname) #debug #Write-Host "value of emailtoaddress is: "$EmailToAddress #Write-Host "value of emailsubject is: "$EmailSubject #Write-Host "value of emailbodywarning is: "$EmailBodyWarning #Write-Host "value of daystoexpire is: "$daystoexpire #Write-Host "value of expires is: "$expires #Write-Host "value of firstname is: "$firstname #Fix remove decimal $daystoexpire = "{0:N0}" -f $daystoexpire $htmlbody = '' $htmlbody += '' $htmlbody += '' $htmlbody += $EmailBodyWarning $htmlbody += '
' #Dynamic content based on days remaining before password expires if ($daystoexpire -ge 0 -and $daystoexpire -lt 1) { $currenttime =get-date $timeremaining = (New-TimeSpan -Start $currenttime -End $expires).Hours $htmlbody += '

Expires in '+$timeremaining+' Hours - Change Now!

' } if ($daystoexpire -ge 1 -and $daystoexpire -lt 2) { $htmlbody += '

1 Day Remaining!

' } if ($daystoexpire -ge 2 -and $daystoexpire -lt 22) { $htmlbody += '

'+$daystoexpire+' Days Remaining.

' } $htmlbody += '' $htmlbody += $PasswordComplexityRequirements $htmlbody += '

' $htmlbody += $MaxPasswordAgeNotice $htmlbody += '

' $htmlbody += $PasswordChangeInstructions $htmlbody += '
' $htmlbody += 'Thank you,' $htmlbody += '

' $htmlbody += $EmailFromName $htmlbody += '

' $htmlbody += '' $htmlbody += $EmailFromAddress $htmlbody += '' $htmlbody += $FromPhoneNumber $htmlbody += ' ' $htmlbody += '' $finalhtmlbody = $htmlbody Write-Host "Sending Email to Staff "$EmailToAddress "..." #Debug commented out send - printing html to screen to review Write-Host "Email Body to Send:" Write-Host $finalhtmlbody Send-MailMessage -From $EmailFromAddress -To $EmailToAddress -Subject $EmailSubject -Body $finalhtmlbody -BodyAsHtml -SmtpServer $EmailServer $htmlbody = '' $finalhtmlbody = '' return } # #Function for Manager Email Send #Variables In: ($ManagerEmailToAddress, $ManagerFirstname, $StaffName, $EmailSubject, $EmailBodyWarning, $daystoexpire, $expires) # function ManagerProcessEmail(){ param([string]$ManagerEmailToAddress, [string]$ManagerFirstname, [string]$StaffName, [string]$firstname, [Double]$daystoexpire, [string]$expires) #### #debug #Write-Host "value of manageremailtoaddress is: "$ManagerEmailToAddress #Write-Host "value of managerfirstnane is: "$ManagerFirstname #Write-Host "value of staffname is: "$StaffName #Write-Host "value of stafffirstname is: "$firstname #Write-Host "value of daystoexpire is: "$daystoexpire #Write-Host "value of expires is: "$expires $htmlbody = '' $htmlbody += '' $htmlbody += ' ' $htmlbody += 'Notice: Your staff member: '+$StaffName+' has their '+$CompanyName+' network password about to expire.' $htmlbody += 'You are receiving this notification because this staff member has not yet acted to update their password on their own.
' #Dynamic content based on days remaining before password expires if ($daystoexpire -ge 0 -and $daystoexpire -lt 1) { $currenttime =get-date $timeremaining = (New-TimeSpan -Start $currenttime -End $expires).Hours $htmlbody += '

Expires in '+$timeremaining+' Hours!

' } if ($daystoexpire -ge 1 -and $daystoexpire -lt 2) { $htmlbody += '

1 Day Remaining!

' } $htmlbody += '' $htmlbody += $PasswordComplexityRequirements $htmlbody += '

' $htmlbody += $MaxPasswordAgeNotice $htmlbody += '

Please ask '+$firstname+' to change their password following these instructions or they may be locked out tomorrow.

' $htmlbody += $PasswordChangeInstructions $htmlbody += '
' $htmlbody += 'Thank you,' $htmlbody += '

' $htmlbody += $EmailFromName $htmlbody += '

' $htmlbody += '' $htmlbody += $EmailFromAddress $htmlbody += '' $htmlbody += $FromPhoneNumber $htmlbody += ' ' $htmlbody += '' $finalhtmlbody = $htmlbody Write-Host "Sending Email to Manager "$ManagerEmailToAddress "..." #Debug commented out send - printing html to screen to review Write-Host "Email Body to Send:" Write-Host $finalhtmlbody Send-MailMessage -From $EmailFromAddress -To $ManagerEmailToAddress -Subject $EmailSubject -Body $finalhtmlbody -BodyAsHtml -SmtpServer $EmailServer $htmlbody = '' $finalhtmlbody = '' return } Write-Host "Starting the User Password Expiration Email Notification Script" Write-Host "Start time: "$scriptexecutetime Write-Host "Processing User Password Expiration Schedules..." # # add logic to avoid null email address (!=null ) # (Get-ADUser -filter {(Enabled -eq "True") -and (PasswordNeverExpires -eq "False")} -properties SamAccountName,msDS-UserPasswordExpiryTimeComputed,PasswordExpired,PasswordLastSet,PasswordNeverExpires,PasswordNotRequired,LastLogonDate,Manager,EmailAddress | Where-Object $SearchOUCriteria ) | Sort-Object pwdLastSet | foreach-object { Write-Host "Getting staff information..." $lastset=Get-Date([System.DateTime]::FromFileTimeUtc($_.pwdLastSet)) $expires=Get-Date([System.DateTime]::FromFileTimeUtc($_."msDS-UserPasswordExpiryTimeComputed")) $daystoexpire=((New-TimeSpan -Start $(Get-Date) -End $expires).TotalDays) $EmailToAddress = $_.EmailAddress $firstname=$_.GivenName $StaffName = $_.Name $managerID = $_.Manager $samname = $_.SamAccountName Write-Host "Staff Name is: "$StaffName #Debug #Write-Host "Staff: " $StaffName "lastset: " $lastset "expires: " $expires "email: " $EmailToAddress "Days to Expire: " $daystoexpire #Write-Host "ManagerID: " $managerID if(!$managerID) { #No Manager Set Check $adminsummarybody += "
" write-host "getting manager information... Not Set" } else { #Populate Manager variables write-host "getting manager information..." $ManagerDetails = Get-ADUser $_.Manager -Properties EmailAddress, GivenName $ManagerEmailToAddress = $ManagerDetails.EmailAddress $ManagerFirstname = $ManagerDetails.GivenName write-host "Manager is: " $managerEmailToAddress } #Null Email field check if(!$EmailToAddress) { #no email address $adminsummarybody += "" } else { if (($daystoexpire -ge 0 -and $daystoexpire -lt 16) -or ($daystoexpire -ge 18 -and $daystoexpire -lt 19) -or ($daystoexpire -ge 21 -and $daystoexpire -lt 22)) { $ThereAreExpiring = $true if ($daystoexpire -ge 0 -and $daystoexpire -lt 1) { # zero days remaining. $EmailSubject = "$firstname, your $CompanyName password is expiring!" $EmailBodyWarning = "$firstname, Your $CompanyName password is expiring and you must change it immediately." } elseif ($daystoexpire -ge 1 -and $daystoexpire -lt 2) { # one days remaining. $EmailSubject = "$firstname, your $CompanyName password expires tomorrow!" $EmailBodyWarning = "$firstname, Your $CompanyName password has expires soon and you must change it immediately." # notify Manager #Null Email field check if(!$ManagerEmailToAddress) { #no email address $adminsummarybody += "" } if($ManagerEmailToAddress) { ManagerProcessEmail "$ManagerEmailToAddress" "$ManagerFirstname" "$StaffName" "$firstname" "$daystoexpire" "$expires" $manageremailsentcount++ } } elseif ($daystoexpire -ge 18 -and $daystoexpire -lt 22) { # between 18 - 21 days remaining. $EmailSubject = "$firstname, your $CompanyName password expires in "+[math]::Round($daystoexpire)+" days!" $EmailBodyWarning = "$firstname, Your $CompanyName password expires in "+[math]::Round($daystoexpire)+" days." } Else { #email notification for between 15 and 2 days remaining. $EmailSubject = "$firstname, your $CompanyName password expires in "+[math]::Round($daystoexpire)+" days!" $EmailBodyWarning = "$firstname, Your $CompanyName password expires in "+[math]::Round($daystoexpire)+" days." } # Process Email ProcessEmail "$EmailToAddress" "$EmailSubject" "$EmailBodyWarning" "$daystoexpire" "$expires" "$firstname" $emailsentcount++ # Add a note to the admin report email, but don't notify user $adminsummarybody += "" } elseif ($daystoexpire -lt 0) { $ThereAreExpiring=$true # Add a note to the admin report email, but don't notify user. $adminsummarybody += "" } } $ManagerDetails = "" $ManagerEmailToAddress = "" $ManagerFirstname = "" } ## ## Send administrator a confirmation if Expirings found. ## if ($ThereAreExpiring) { Write-Host "Sending Admin Email to "$EmailToAddress "..." $adminsummarybody += "
NameExpiresDays Left
$samname$expires*HAS NO MANAGERID SET
$samname$expires*NO EMAIL ADDRESS
$samname$expiresNO *MANAGER EMAIL ADDRESS
$samname$expires"+[math]::Round($daystoexpire)+"
$samname$expires"+[math]::Round($daystoexpire)+" - Expired
" $adminsummarybody += "

Password Expiration emails sent: " $adminsummarybody += $emailsentcount $adminsummarybody += "
Email Alerts Notifying Managers sent: " $adminsummarybody += $manageremailsentcount $adminsummarybody += "

" $adminsummarybody += "" #debug -toggle off send-mailmessage during testing with # #Write-Host "Admin Email From is: " #Write-Host $EmailFromAddress #Write-Host "Admin To Email is: " #Write-Host $adminEmailToAddress #Write-Host "Admin Subject is: " #Write-Host $adminEmailSubject #Write-Host "Admin Summary is: " #Write-Host $adminsummarybody #Write-Host "Max Password Age for Domain: " $maxdays Send-MailMessage -From $EmailFromAddress -To $AdminEmailToAddress -Subject $AdminEmailSubject -Body $adminsummarybody -BodyAsHtml -SmtpServer $EmailServer } else { #Note to screen Write-Host "No passwords expiring found." Write-Host "Sending Admin Email to "$EmailToAddress "..." $adminsummarybody += "" $adminsummarybody += "

No Expirations but warnings above exist" $adminsummarybody += "

Password Expiration emails sent: " $adminsummarybody += $emailsentcount $adminsummarybody += "
Email Alerts Notifying Managers sent: " $adminsummarybody += $manageremailsentcount $adminsummarybody += "

" $adminsummarybody += "" #debug -toggle off send-mailmessage during testing with # #Write-Host "Admin Email From is: " #Write-Host $EmailFromAddress #Write-Host "Admin To Email is: " #Write-Host $adminEmailToAddress #Write-Host "Admin Subject is: " #Write-Host $adminEmailSubject #Write-Host "Admin Summary is: " #Write-Host $adminsummarybody #Write-Host "Max Password Age for Domain: " $maxdays Send-MailMessage -From $EmailFromAddress -To $AdminEmailToAddress -Subject $AdminEmailSubject -Body $adminsummarybody -BodyAsHtml -SmtpServer $EmailServer } $adminsummarybody = '' $ThereAreExpiring = $false Write-Host "Script has completed Running" $CompetedRun = Get-Date Write-Host "Finish time: " $CompetedRun


Leave a Reply

Your email address will not be published. Required fields are marked *