# Automatically Notify Microsoft 365 Users of Upcoming Password Expiration Using PowerShell & Azure Automation

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:

* **PowerShell**
    
* **Microsoft Graph API**
    
* **Azure Automation (or local execution)**
    

## 📊 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

* Create an app in **Entra ID &gt; App Registrations**
    
* Assign **API Permissions**:
    
    * `User.Read.All`
        
    * `Group.Read.All`
        
    * `Mail.Send`
        
* **Grant Admin Consent**
    
* Generate a **client secret** and note the **Application (Client) ID** and **Directory (Tenant) 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

```plaintext
User: jo*****@domain.com | Days remaining: 5
Sending alert...
Email sent to jo*****@domain.com
```

---

## ✎ Script Usage (Locally or in Azure)

### ⚡ Local Test Example:

```plaintext
.\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:

* Import the script as a **Runbook**
    
* Set up a **daily schedule**
    
* Securely store secrets using **Automation Variables**
    

---

## 🔧 Under the Hood (Logic Breakdown)

1. Get access token using `client_credentials`
    
2. Connect to Microsoft Graph
    
3. Fetch users from the target group
    
4. 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**](https://github.com/bitnash/m365-powershell-scripts/tree/main/password-expiry-alert)

---

## 📈 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! ✨
