Microsoft 365: Password Expiration Notification Email
Password expiration notifications play a crucial role in maintaining the security of your organization’s Microsoft 365 accounts. Ensuring users are aware of upcoming password expirations can help prevent account lockouts and encourage users to create strong, unique passwords. In this guide, we will demonstrate how to create a Microsoft Graph PowerShell script that automatically sends email notifications to users when their Office 365 passwords are nearing expiration.
What is a Password Expiry Notification Email?
A password expiry notification email is a message that is sent to a user when their password is about to expire. The email typically includes information about the password expiration date and instructions on how to change the password. Password expiry notification emails are an essential tool for organizations that want to ensure that their users change their passwords regularly and keep their accounts secure.
How to Send Password Expiration Notification Emails in Microsoft 365?
As the Password expiration notifications are no longer supported in the Microsoft 365 admin center (Maybe because Microsoft recommends disabling password expiration!), we must implement a Windows PowerShell script-based solution. To create a Microsoft Graph PowerShell script for Office 365 password expiration notifications, follow these steps:
Pre-requisites: Install the Microsoft Graph PowerShell Module. You need the Microsoft Graph PowerShell module installed on your computer. Use: Install-Module Microsoft.Graph
.
Use this PowerShell script to send out an Email reminder to all users whose password is expiring:
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "User.Read.All", "Mail.Send"
# Set the notification threshold - days before password expires
$NotificationThreshold = 7
$PasswordExpiryThreshold = 90 #By default 90 days Password expiry
# Get all users
$AllUsers = Get-MgUser -All -Property Id, DisplayName, UserPrincipalName,Mail,UserType, AccountEnabled,PasswordPolicies,lastPasswordChangeDateTime
# Iterate through each user
ForEach ($User in $AllUsers)
{
# Skip disabled accounts and users with Password never Expire flag
If (!$User.AccountEnabled -or $User.PasswordPolicies -contains "xDisablePasswordExpiration" -or $User.userType -eq "Guest") {
continue
}
# Get user's password Expiry Date
$PasswordExpiryDate = $User.lastPasswordChangeDateTime.AddDays($PasswordExpiryThreshold)
# Calculate the remaining days
$RemainingDays = ($PasswordExpiryDate - (Get-Date)).Days
# Check if the remaining days are within the notification threshold
If ($RemainingDays -le $NotificationThreshold) {
# Send an email notification to the user
$EmailBody = "
Hello $($User.DisplayName),
<br/><br/>
Your Office 365 password will expire in $remainingDays days. Please change your password before it expires to avoid any disruption in accessing your account.
<br/><br/>
To change your password, follow these steps:<br/>
<ol>
<li>Sign in to Office 365 (https://www.office.com)</li>
<li>Click on your profile picture in the top right corner.</li>
<li>Select 'View account'.</li>
<li> Click 'Password'.</li>
<li> Follow the instructions to change your password.</li>
</ol>
<br/>
Thank you,<br/>
IT Support Team
"
$MailParams = @{
Message = @{
Subject = "Your Office 365 password will expire soon"
Importance = "High"
Body = @{
ContentType = "html"
Content = $EmailBody
}
ToRecipients = @(
@{
EmailAddress = @{
Address = $User.Mail
}
}
)
}
}
# Send the email using Microsoft Graph
Send-MgUserMail -UserId $User.Mail -BodyParameter $MailParams
}
}
This script will prompt for login credentials and iterate through all users in your organization, calculate the password expiration date, and send an email notification to users whose passwords will expire within the specified threshold (7 days, in our case). You can modify the $NotificationThreshold
variable to adjust the number of days before the password expires when notifications are sent.
Here is the script in action:
Automate the Password Expiry Reminder Emails
For an unattended automated scenario, follow these steps:
Step 1: Create an App ID and Grant Permissions
Create an app ID in Azure AD to connect with Microsoft Graph: How to Connect to the Microsoft Graph PowerShell module? Make sure you grant “User.Read.All” and “Mail.Send” permissions to the App ID.
Step 2: Update the Parameters in this PowerShell Script
Once ready with the App ID, update this PowerShell script’s parameters section. Here is how this script works:
- Connects to Microsoft Graph using the given App ID and certificate thumbprint
- Checks the password expiration date of all users – Excludes users with Password never expires, password already expired, guest users, etc.
- Sends an Email to users whose password expires within the given threshold (15 days as in the script!) from a given Email ID (Make sure you have the Email created already. E.g., In our case, it’s: $SenderID = “Helpdesk@Crescent.com”).
- Logs the message to a log file.
#Parameters
$TenantID = "c1c2b123-4240-4775-a19a-6351b30cx2f6"
$ClientID = "3c1541f7-9565-4abe-b398-f47ac91c2c06" #App ID
$CertThumbPrint = "63FDDD207DE01C0EB34C35647D086D3C1520FA7"
#Path for Log File
$LogFilePath = "C:\Scripts\PasswordExpiry.Log"
$SenderID = "Helpdesk@Crescent.com"
#Notification threshold - days before password expires
$NotificationThreshold = 15
$PasswordExpiryThreshold = 90 #By default 90 days Password expiry
#Function to Add Content to a Log File
Function Write-Log {
[CmdletBinding()]
Param ([Parameter(Mandatory=$true)][string]$Message)
Process{
#Add Message to Log File with timestamp
"$([datetime]::Now) : $Message" | Out-File -FilePath $LogFilePath -append;
#Write the log message to the screen
Write-host $([datetime]::Now) $Message
}
}
#Connect to Microsoft Graph using App
Connect-MgGraph -ClientID $ClientID -TenantId $TenantID -CertificateThumbprint $CertThumbPrint
#Ensure the Parent Folder for Log File
$FolderPath= Split-Path $LogFilePath
If(!(Test-Path -path $FolderPath)) {
New-Item -ItemType directory -Path $FolderPath | Out-Null
}
# Get all users
$AllUsers = Get-MgUser -All -Property Id, DisplayName, UserPrincipalName,Mail,UserType, AccountEnabled,PasswordPolicies,lastPasswordChangeDateTime
# Iterate through each user
ForEach ($User in $AllUsers)
{
# Skip disabled accounts and users with Password never Expire flag
If (!$User.AccountEnabled -or $User.PasswordPolicies -contains "DisablePasswordExpiration" -or $User.userType -eq "Guest") {
continue
}
# Get user's password Expiry Date
$PasswordExpiryDate = $User.lastPasswordChangeDateTime.AddDays($PasswordExpiryThreshold)
# Calculate the remaining days
$RemainingDays = ($PasswordExpiryDate - (Get-Date)).Days
# Check if the remaining days are within the notification threshold
If ($RemainingDays -le $NotificationThreshold -and $RemainingDays -ge 0) {
# Send an email notification to the user
$EmailBody = "
Hello $($User.DisplayName),
<br/><br/>
Your Office 365 password will expire in $remainingDays days. Please change your password before it expires to avoid any disruption in accessing your account.
<br/><br/>
To change your password, follow these steps:<br/>
<ol>
<li>Sign in to Office 365 (https://www.office.com)</li>
<li>Click on your profile picture in the top right corner.</li>
<li>Select 'View account'.</li>
<li> Click 'Password'.</li>
<li> Follow the instructions to change your password.</li>
</ol>
<br/>
Thank you,<br/>
IT Support Team
"
$MailParams = @{
Message = @{
Subject = "Your Office 365 password will expire soon"
Importance = "High"
Body = @{
ContentType = "html"
Content = $EmailBody
}
ToRecipients = @(
@{
EmailAddress = @{
Address = $User.Mail
}
}
)
}
}
# Send the email using Microsoft Graph
Send-MgUserMail -UserId $SenderID -BodyParameter $MailParams
#Write to Log File
Write-Log "Password Expiration Notification sent to user $($User.Mail) - Password Expires on $PasswordExpiryDate"
}
}
This script could be a huge productivity saver, Since without proper notifications, users may be caught off-guard when their passwords expire, leading to account lockouts and disruptions in productivity. These emails will notify users that their password is about to expire and should change it to avoid any disruption.
Step 3: Schedule the PowerShell Script
You can create an automated system for sending password expiration notification emails to your Office 365 users: Use Schedule the PowerShell Script using Windows Tasks Scheduler or Automate the PowerShell Execution with Azure Runbook.
By following our step-by-step instructions, you will be able to help users stay informed about their password expiration dates and maintain secure access to their Office 365 accounts.
Best Practices for Password Expiry Notification Emails
Here are some best practices that organizations should follow when implementing password expiry notification emails:
- Ensure that users receive notification emails well in advance of their password expiration date. This will give them enough time to change their password without disrupting their work.
- Provide clear instructions on how to change passwords. Include links to resources that users can use to change their passwords.
- Encourage users to create strong, complex passwords that are difficult to guess or crack.
- Consider implementing multi-factor authentication to add an extra layer of security to user accounts.
- Regularly review your password policy to ensure that it is up to date and aligned with industry best practices.
Conclusion:
With the Microsoft Graph PowerShell script for Office 365 password expiration notifications, you can automate the process of reminding users to update their passwords before they expire. This proactive approach helps users stay informed about their password expiration dates, reduces the risk of account lockouts, and promotes a secure environment for your organization. Implementing this Microsoft Graph PowerShell solution can enhance your organization’s security and maintain seamless access to Office 365 resources while promoting a secure environment for all users.
To set the password to never expire for Office 365 user accounts, You can use the Azure Active Directory PowerShell or Microsoft Graph API PowerShell cmdlets. You can also disable the password expiration for your organization through the password expiration policy in Office 365 Admin Center (Settings >> then click “Org settings” >> “Security & Privacy” >> Select Password Expiration Policy >> Check the box next to “Set user passwords to never expire”).
More info: Disable password expiration in Office 365
Password expiration notifications are no longer supported in Microsoft 365! So, you must setup your workaround to send users Password Expiration Emails.
90 days from the last password change date (It’s disabled by default). However, Global Admin can configure the password expiry duration to meet the organization’s security requirements through the Office 365 Admin Center or PowerShell.
When an Office 365 current password expires, the user will be prompted to change it the next time they sign in. If the user ignores the prompt after the actual expiration date and does not change their password, they will be locked out of their account until they reset their password (and the technical support at admin level can unlock it). However, Microsoft Office applications like Outlook may continue to work until the password expires in the cache.
Yes! Password expiration is no longer recommended as a security measure, as it does more harm than good. Changing passwords every 90 days could leave exposed weak/old passwords usable by a hacker/scammers/cybercriminals for up to three months, and it is far better to require strong passwords and use multi-factor authentication.
When I try to automate this, I get the following error in Automation Runbook when testing it out:
System.Management.Automation.CommandNotFoundException: The term ‘Connect-MgGraph’… etc.
I’ve installed the Msgraph module in the module section of the run book. What am I missing/doing wrong?
Hello and thank you for the blog post. I am running into the following error when running this script
Send-MgUserMail : Access is denied. Check credentials and try again.
At line:55 char:5
+ Send-MgUserMail -UserId $User.Mail -BodyParameter $MailParams
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ({ UserId = jcon…ionJsonSchema }:f__AnonymousType8`2) [Send-MgUserMail_Send1], RestException`1
+ FullyQualifiedErrorId : ErrorAccessDenied,Microsoft.Graph.PowerShell.Cmdlets.SendMgUserMail_Send1
Send-MgUserMail : Access is denied. Check credentials and try again.
At line:55 char:5
+ Send-MgUserMail -UserId $User.Mail -BodyParameter $MailParams
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ({ UserId = jcou…ionJsonSchema }:f__AnonymousType8`2) [Send-MgUserMail_Send1], RestException`1
+ FullyQualifiedErrorId : ErrorAccessDenied,Microsoft.Graph.PowerShell.Cmdlets.SendMgUserMail_Send1
Could you ensure you have granted “User.Read.All” and “Mail.Send” permissions to the App ID in Azure ad?
Hi, thank for the script..
I notice also that the local log add only the last user to the file, if more than one user password are expired, only the last user is written into the file log. Can we change the script to add all users expired to the logs? Can we also create a file everyday instead of rewrite the same?
Thanks
Fixed it Alessandro! To create a new log file every day (based on the date), Please refer: How to Create a Log File in PowerShell?
Thank you, how can I test this with few users?
Sure! Instead of “Get-MgUser -All”, use: “Get-MgUser -Top 10”