Ensuring your Microsoft 365 users are aware of password expiration is critical for both security and productivity. Without proper notification, users can get locked out unexpectedly, causing support overhead and frustration. While Microsoft 365 doesn't send these notifications by default, we can fix that.
In this guide, you'll learn how to automate password expiration checks and send timely email alerts using:
π What This Script Does
Connects to Microsoft Graph using App Registration
Retrieves users from a dynamic Microsoft 365 group
Checks their last password change date
Calculates days until expiration (based on org policy)
Sends custom email notifications for users whose passwords will expire soon (e.g., within 7 days)
π‘ Note: The script assumes all users in the dynamic group have passwords that do expire (e.g., users logging in via Microsoft Entra ID Join). Therefore, it does not need to filter out accounts with PasswordNeverExpires, since the group logic already excludes them.
π Pre-Requisites
1. App Registration in Entra ID
2. Licensed Sender Mailbox
Ensure your app is authorized to send mail on behalf of a licensed user, such as noreply@yourdomain.com.
3. Optional: Azure Automation Setup
Store sensitive variables as Automation Variables:
ClientID
ClientSecret
TenantID
GroupId
SenderEmail
PasswordExpirationDays
π‘ Features of the Script
Can run locally or inside Azure Automation
Smart logging via Write-Log (supports verbosity and silent automation)
UPN masking for privacy in logs
Error handling and graceful exits
πΊ Masked Logging Example
User: jo*****@domain.com | Days remaining: 5
Sending alert...
Email sent to jo*****@domain.com
β Script Usage (Locally or in Azure)
β‘ Local Test Example:
.\Notify-M365PasswordExpiry.ps1 `
-ClientId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
-ClientSecret "your-secret" `
-TenantId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
-GroupId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
-PasswordExpirationDays 45 `
-SenderEmail "noreply@yourdomain.com" `
-UseLocalParameters
π Scheduled in Azure Automation:
π§ Under the Hood (Logic Breakdown)
Get access token using client_credentials
Connect to Microsoft Graph
Fetch users from the target group
For each user:
Get LastPasswordChangeDateTime
Add org-defined expiration window (e.g., 45 days)
Calculate remaining days
If within 7 days, send email
π§© Key Functions Explained
π Get-GraphAccessToken
Authenticates using client credentials and retrieves a Microsoft Graph API access token.
π Connect-ToGraph
Uses the Microsoft Graph PowerShell SDK to establish a session for additional operations like retrieving user data.
π₯ Get-GroupUsers
Fetches members from the specified dynamic group by Group ID.
π Get-UserDetails
Retrieves DisplayName, UserPrincipalName, and LastPasswordChangeDateTime for each user.
β Send-EmailNotification
Sends a formatted HTML email to users using Microsoft Graph's sendMail endpoint. The message content is fully customizable based on your organizationβs communication style.
π GitHub Repository
You can find the full script and future updates here: π GitHub β Notify-M365PasswordExpiry.ps1
π Benefits
Reduces help desk tickets
Keeps users informed and proactive
Flexible: can run in the cloud or on-prem
Secure: supports masked logging and stored secrets
π What You Can Improve Next
Integrate Microsoft Teams alerts
Write logs to Azure Storage or Log Analytics
Localize email messages based on user locale (optional β currently defaulted to English)
π Final Thoughts
This script gives you full control over Microsoft 365 password expiration reminders, with enterprise-grade flexibility. Whether you run it in Azure Automation or locally, it's ready to scale and secure.
Have questions or want enhancements? Let's build on this together! β¨