All scripts
Governance 543
Get-EntraAppSecretExpiryReport
Scans every Entra ID app registration and flags client secrets and certificates that are expired or expiring soon, so you catch broken automation before it breaks.
Get-EntraAppSecretExpiryReport.ps1
<#
.SYNOPSIS
Reports Entra ID app registrations with client secrets or certificates that are expired or expiring soon.
.DESCRIPTION
Connects to Microsoft Graph and checks every app registration in the tenant for
client secrets and certificates that have already expired or will expire within
a chosen number of days. Expired app credentials are one of the most common causes
of silent automation failures, this catches them before they cause an outage.
.PARAMETER DaysThreshold
Number of days ahead to check for upcoming expiry. Defaults to 30.
.PARAMETER ExportPath
Optional path to export the results as CSV.
.EXAMPLE
.\Get-EntraAppSecretExpiryReport.ps1 -DaysThreshold 60 -ExportPath C:\Reports\AppSecrets.csv
.AUTHOR
Shehryar Hassan
#>
[CmdletBinding()]
param(
[int]$DaysThreshold = 30,
[string]$ExportPath
)
# Requires: Install-Module Microsoft.Graph -Scope CurrentUser
Import-Module Microsoft.Graph.Applications -ErrorAction Stop
Connect-MgGraph -Scopes "Application.Read.All" -NoWelcome
$cutoffDate = (Get-Date).AddDays($DaysThreshold)
$results = @()
Write-Host "Checking app registrations for credentials expiring within $DaysThreshold days..." -ForegroundColor Cyan
$apps = Get-MgApplication -All -Property Id, DisplayName, AppId, PasswordCredentials, KeyCredentials
foreach ($app in $apps) {
foreach ($secret in $app.PasswordCredentials) {
if ($secret.EndDateTime -le $cutoffDate) {
$daysLeft = [math]::Round(((Get-Date $secret.EndDateTime) - (Get-Date)).TotalDays, 0)
$results += [PSCustomObject]@{
AppName = $app.DisplayName
AppId = $app.AppId
CredentialType = "Secret"
CredentialName = $secret.DisplayName
ExpiresOn = $secret.EndDateTime
DaysLeft = $daysLeft
Status = if ($daysLeft -lt 0) { "Expired" } else { "Expiring soon" }
}
}
}
foreach ($cert in $app.KeyCredentials) {
if ($cert.EndDateTime -le $cutoffDate) {
$daysLeft = [math]::Round(((Get-Date $cert.EndDateTime) - (Get-Date)).TotalDays, 0)
$results += [PSCustomObject]@{
AppName = $app.DisplayName
AppId = $app.AppId
CredentialType = "Certificate"
CredentialName = $cert.DisplayName
ExpiresOn = $cert.EndDateTime
DaysLeft = $daysLeft
Status = if ($daysLeft -lt 0) { "Expired" } else { "Expiring soon" }
}
}
}
}
$results = $results | Sort-Object DaysLeft
if ($results.Count -eq 0) {
Write-Host "No app credentials expiring within $DaysThreshold days." -ForegroundColor Green
}
else {
$results | Format-Table AppName, CredentialType, ExpiresOn, DaysLeft, Status -AutoSize
$expiredCount = ($results | Where-Object { $_.Status -eq "Expired" }).Count
if ($expiredCount -gt 0) {
Write-Host "$expiredCount credential(s) have already expired. Fix these first." -ForegroundColor Red
}
}
if ($ExportPath) {
$results | Export-Csv -Path $ExportPath -NoTypeInformation
Write-Host "Exported to $ExportPath" -ForegroundColor Cyan
}
Disconnect-MgGraph | Out-Null
Read it before you run it, and test in a safe tenant first.