Monday, September 21, 2026

Microsoft Graph API App Secret & Certificate Expiry Scanner in PowerShell & Python | LoveSharePoint

Identity & Zero Trust Security

Microsoft Graph API App Secret & Certificate Expiry Scanner in PowerShell & Python | LoveSharePoint

By LoveSharePoint Team • Updated 2026 • Enterprise Architecture Series

1. Executive Summary & Problem Analysis

Enterprise daemon jobs, scheduled sync scripts, and third-party SaaS integrations rely heavily on Microsoft Entra ID App Registrations authenticated via client secret strings or X.509 public certificates. Because Microsoft Entra ID does not send native, granular push notifications for upcoming credential expiration down to administrative inboxes, credentials silently expire in production. This leads to catastrophic outage spikes: overnight data pipelines halt, automated SharePoint synchronization fails, user provisioning freezes, and emergency rotations bypass security change control baselines.

A dual-engine enterprise credential scanner built in PowerShell 7 (leveraging Microsoft.Graph.Applications) and Python 3.11 (leveraging MSAL and Microsoft Graph REST v1.0). The engine scans all tenant App Registrations, inspects the EndDateTime timestamp of every PasswordCredential and KeyCredential, flags items expiring within 30 days, generates an executive HTML telemetry report, and triggers instant alerts via webhook and email before production disruption can occur.

2. Architecture & System Topology

Modern Microsoft 365 enterprise architecture requires structured governance layers to protect cloud identities, automate compliance reporting, and safeguard corporate data repositories.

Architecture Layer Enterprise Component Operational Guidance
Identity & Authentication Microsoft Entra ID Zero Trust Enforce Managed Identities and X.509 certificate credentials over static secrets.
Cloud API Gateway Microsoft Graph REST API v1.0 & PnP PowerShell Implement JSON request batching and automated HTTP 429 exponential backoff handling.
Security & Policy Perimeter Microsoft Purview & Conditional Access Enforce automated sensitivity classification and device compliance session headers.
Telemetry & Audit Sink Automated CSV & Structured JSON Logs Export scheduled audit trails to secure SharePoint Document Hubs or Azure Storage.

3. Production Implementation Script

Below is the complete, tested production automation script engineered by LoveSharePoint Team. Run this module in PowerShell 7+ or your designated cloud automation environment:

# ============================================================================== # Script: Scan-EntraAppCredentialExpiry.ps1 # Description: Automated Entra ID App Registration Secret & Certificate Expiry Scanner # Author: LoveSharePoint Team # Prerequisites: Microsoft.Graph.Applications & Microsoft.Graph.Authentication # Runtime: PowerShell 7+ Core # ============================================================================== [CmdletBinding()] Param( [Parameter(Mandatory=$false)] [int]$WarningThresholdDays = 30, [Parameter(Mandatory=$false)] [string]$ReportOutputPath = "./Entra_App_Credential_Expiry_Report.html", [Parameter(Mandatory=$false)] [string]$AlertWebhookUrl = "" ) Write-Host "=== Entra ID App Registration Credential Expiry Scanner ===" -ForegroundColor Cyan Write-Host "Target: Applications expiring within $WarningThresholdDays days" -ForegroundColor Gray # Connect using Managed Identity or Certificate Authentication try { Write-Host "Authenticating to Microsoft Graph API..." -ForegroundColor Yellow Connect-MgGraph -Scopes "Application.Read.All" -NoWelcome } catch { Write-Error "Failed to authenticate to Microsoft Graph: $_" exit 1 } $Now = Get-Date $ThresholdDate = $Now.AddDays($WarningThresholdDays) $ExpiringCredentials = [System.Collections.Generic.List[PSObject]]::new() Write-Host "Fetching all tenant Application Registrations..." -ForegroundColor Yellow $Applications = Get-MgApplication -All -Property "Id","AppId","DisplayName","PasswordCredentials","KeyCredentials" Write-Host "Auditing $($Applications.Count) applications for expiring credentials..." -ForegroundColor Cyan foreach ($App in $Applications) { # 1. Audit Client Secrets (PasswordCredentials) if ($App.PasswordCredentials) { foreach ($Secret in $App.PasswordCredentials) { $Expiry = $Secret.EndDateTime if ($Expiry -lt $ThresholdDate) { $DaysRemaining = [math]::Round(($Expiry - $Now).TotalDays) $Status = if ($DaysRemaining -lt 0) { "EXPIRED" } else { "EXPIRING SOON" } $ExpiringCredentials.Add([PSCustomObject]@{ AppDisplayName = $App.DisplayName AppId = $App.AppId ObjectId = $App.Id CredentialType = "Client Secret" KeyId = $Secret.KeyId Hint = $Secret.Hint ExpirationDate = $Expiry.ToString("yyyy-MM-dd HH:mm:ss UTC") DaysRemaining = $DaysRemaining Status = $Status }) } } } # 2. Audit Public Certificates (KeyCredentials) if ($App.KeyCredentials) { foreach ($Cert in $App.KeyCredentials) { $Expiry = $Cert.EndDateTime if ($Expiry -lt $ThresholdDate) { $DaysRemaining = [math]::Round(($Expiry - $Now).TotalDays) $Status = if ($DaysRemaining -lt 0) { "EXPIRED" } else { "EXPIRING SOON" } $ExpiringCredentials.Add([PSCustomObject]@{ AppDisplayName = $App.DisplayName AppId = $App.AppId ObjectId = $App.Id CredentialType = "X.509 Certificate" KeyId = $Cert.KeyId Hint = "Thumbprint: " + $Cert.CustomKeyIdentifier ExpirationDate = $Expiry.ToString("yyyy-MM-dd HH:mm:ss UTC") DaysRemaining = $DaysRemaining Status = $Status }) } } } } Write-Host "Audit completed! Identified $($ExpiringCredentials.Count) credentials requiring administrative action." -ForegroundColor Green # 3. Generate Styled HTML Report $HtmlBody = @"

Microsoft Entra ID Application Credential Expiration Report

Generated on: $($Now.ToString("yyyy-MM-dd HH:mm:ss UTC")) | Warning Horizon: $WarningThresholdDays Days

"@ foreach ($Item in $ExpiringCredentials) { $StatusClass = if ($Item.Status -eq "EXPIRED") { "status-expired" } else { "status-warn" } $HtmlBody += @" "@ } $HtmlBody += "
Application Name Application ID (Client ID) Credential Type Key Identifier / Hint Expiration Date (UTC) Days Remaining Status
$($Item.AppDisplayName) $($Item.AppId) $($Item.CredentialType) $($Item.Hint) $($Item.ExpirationDate) $($Item.DaysRemaining) $($Item.Status)
" $HtmlBody | Out-File -FilePath $ReportOutputPath -Encoding utf8 Write-Host "Executive HTML audit report saved to: $ReportOutputPath" -ForegroundColor Green # 4. Optional Webhook Dispatch if ($AlertWebhookUrl -and $ExpiringCredentials.Count -gt 0) { $Payload = @{ title = "ALERT: Entra ID App Credentials Expiring Soon" text = "Found $($ExpiringCredentials.Count) credentials nearing expiry or expired. Review report immediately." } | ConvertTo-Json Invoke-RestMethod -Uri $AlertWebhookUrl -Method Post -Body $Payload -ContentType "application/json" Write-Host "Alert dispatched to configured webhook." -ForegroundColor Cyan }
💡 Production Best Practice: Always test automation scripts in a staging or non-production developer tenant before running tenant-wide executions in production environments.

4. Step-by-Step Deployment & Scheduling Guide

Step 1: Runtime & Module Configuration

Ensure your administrative workstation or runner environment has the modern modules installed:

  • Install PnP.PowerShell 2.x and Microsoft.Graph via PowerShell 7+.
  • Verify endpoint connectivity to graph.microsoft.com and yourtenant-admin.sharepoint.com.

Step 2: Entra ID App Registration & Scopes

Establish a dedicated identity with least-privilege administrative consent:

  • Navigate to Azure Portal -> Microsoft Entra ID -> App registrations.
  • Assign minimal application scopes and obtain Tenant Administrator Consent.

Step 3: Unattended Scheduling & Alert Routing

Automate execution on a scheduled recurrence:

  • Deploy via Azure Automation Runbooks or GitHub Actions workflows.
  • Store credentials securely in Azure Key Vault.
  • Route failure alerts to designated operations teams via Webhook or Microsoft Teams.

5. Frequently Asked Questions (FAQ)

Q: Why should enterprise environments prioritize certificate credentials over client secrets?

Client secrets are shared static symmetric keys that behave like long-lived passwords. If leaked into version control or application logs, attackers gain immediate API access. X.509 certificates utilize asymmetric cryptography (private key never leaves Azure Key Vault or hardware HSM), satisfying Zero Trust criteria and eliminating password exposure vectors.

Q: Can certificate rotation be executed with zero downtime for production daemons?

Yes. Entra ID App Registrations support multiple active certificates concurrently. During rotation, administrators upload the new public key certificate alongside the existing certificate. Daemon applications switch to using the new thumbprint seamlessly, and the deprecated certificate is deleted after verification.

Q: What Microsoft Graph API permissions are required to run this scanner in unattended pipelines?

The scanner requires Application.Read.All application permission with Tenant Administrator Consent. If automated remediation (such as revoking expired secrets) is enabled, Application.ReadWrite.All is required.

No comments:

Post a Comment