🔐 Proactive Azure App Security: How to Automate Secret Expiry Alerts with PowerShell

My name is Marco Notarrigo and I am a System Engineer with a passion for Technology, Math and Computer Science. Since I was a kid, I began programming on 8-bit computers such as the Apple II and the Commodore 64. As my passion for technology and computer science has grown over the years, it has turned into a job for me.
Over the last years, I have gained experience in DevOps, Security and Cloud Computing, making me well-versed in the principles and practices of these critical fields.
Therefore, I want to share this passion with all of you who follow me and hope to inspire you to pursue your interests.
If you're managing Azure App Registrations across multiple environments or teams, you've probably dealt with expiring client secrets at the worst possible time; usually right before something breaks. 😅
Let’s fix that.
In this post, I’ll walk you through a PowerShell solution I built to automatically audit Azure App secrets and notify you before they expire; with a clean HTML report and optional email alerts.
🚨 Why You Need This
App secrets don’t last forever (nor should they). They typically expire in 6–12 months, but there’s no built-in alerting system from Azure unless you build one yourself.
Miss a secret rotation? Suddenly, your production app can’t authenticate, and you’re scrambling to debug authentication failures during a deploy.
This script automates:
✅ Checking all Azure App Registrations
✅ Identifying secrets expiring in the next N days
✅ Generating a sortable HTML report (When running script with UseLocalParameters)
✅ Sending it via email
🛠️ How It Works
The script uses the Microsoft Graph API to authenticate using a service principal (client ID/secret) and fetch all application registrations. It then;
Filters secrets that expire within a configurable number of days (default: 30)
Generates a styled HTML report (saves it locally)
Sends an email report using Microsoft Graph's
sendMailendpoint
Bonus: If you include a line like NotifyEmail = team@yourdomain.com in the app’s Notes field, it’ll extract that automatically and show it in the report.
🚀 Getting Started
🧾 Prerequisites
1. App Registration in Entra ID
Create an app in Entra ID > App Registrations
Assign API Permissions:
Application.Read.AllDirectory.Read.AllMail.Send
2. Licensed Sender Mailbox
Ensure your app is authorized to send mail on behalf of a licensed user, such as noreply@yourdomain.com.
3. Installed modules;
* Microsoft.Graph.Applications
* Microsoft.Graph.Users
* Microsoft.Graph.Authentication
4. Optional: Azure Automation Setup
Store sensitive variables as Automation Variables:
ClientIDClientSecretTenantIDWarningDaysSenderEmailToEmail
💻 Local Usage
Here’s how to run it locally with manual parameters:
powershellCopyEdit.\Notify-AppSecretExpire.ps1 `
-ClientId "<your-client-id>" `
-ClientSecret "<your-client-secret>" `
-TenantId "<your-tenant-id>" `
-SenderEmail "noreply@yourdomain.com" `
-ToEmail "admin@yourdomain.com" `
-OutputPath "C:\Reports\AppSecretsExpirationReport.html" `
-UseLocalParameters
☁️ Azure Automation Usage
If you're running this in an Azure Automation Account, you don’t need to pass parameters. Instead, define Automation Variables like:
ClientIdClientSecretTenantIdSenderEmailToEmail
The script auto-detects that it's running in Automation and pulls these values in.
📄 What the Report Looks Like
The script outputs a responsive, clean HTML report with:
App name and ID
Secret name (linked to the Azure portal)
Expiration date and days remaining
Optional NotifyEmail extracted from notes
Clickable column headers for sorting
Here’s a preview of the UI;
(This is an example of the generated HTML report)
🔗 GitHub Repository
All the code is available here:
👉 GitHub – secret-expiry-alert
🔔 New Feature: Notify Application Owners via NotifyEmail
In the latest version of the script (last edited June 20, 2025), there’s now support for automatically notifying the responsible team for each Azure AD App Registration using a custom tag in the app’s branding properties.
✅ How It Works
You can specify a NotifyEmail tag in the Notes field under Branding & properties of an App Registration:
NotifyEmail=team-azureops@yourdomain.comWhen the script runs, it searches for this tag in
Internal Notesand extracts the email address.If credentials (client secrets or certificates) are expiring within the configured warning window (e.g. 30 days), the script:
Sends a HTML report to the global ToEmail.
Sends a separate, targeted email to each unique NotifyEmail recipient with only the credentials related to their apps.
✏️ Example Usage in Branding properties:
Go to Azure Portal → Entra ID → App Registrations → [Your App] → Branding & Properties
In the Internal Notes add:
NotifyEmail=team-azureops@yourdomain.com
📄 Script Changes Summary
| Feature | Description |
| NotifyEmail parsing | Reads from Internal Notes for NotifyEmail=<email> |
| Per‑team alerts | Sends a separate email to each unique NotifyEmail address with only relevant expiring credentials |
| Fallback behavior | If no NotifyEmail is defined, a credential expiry still appears in the global report, but no separate email is sent |
💡 Benefits of Using NotifyEmail
Eliminates alert noise by notifying only those who need to act.
Ensures accountability by routing alerts to the correct team.
Simplifies onboarding of new apps—just define your tag once and the automation handles the rest.
🤝 Contributions Welcome
Have ideas? Found a bug? Want to add secret expiration to KeyVault secrets too?
Open an issue or send a PR; I’d love to collaborate.
🙌 Final Thoughts
Security is proactive; not reactive.
Automating app secret monitoring is one small investment that saves a lot of future pain.
Let me know if you try this in your environment or have feedback!


