Azure Automation

Monitor App Registration Credential Expiry Using Managed Identity

Identity Security  ·  Microsoft Graph API  ·  No secrets stored  ·  No Office 365 required

AzureManaged IdentityPowerShell Microsoft GraphAzure AutomationEntra ID
← Back to Tech Blogs

📥 Download the PowerShell Script

Ready-to-use Runbook — paste directly into Azure Automation. No secrets, no O365 licence.

⬇ View & Download Script (.ps1)
⚠️

Use at your own risk. Test in a non-production environment first. The author is not responsible for any unintended outcomes.

Overview & Architecture

Azure App Registrations use client secrets and certificates to authenticate. Both expire — and when they do, every application relying on them breaks silently. This Runbook scans every App Registration in your tenant and flags expired or expiring-soon credentials directly in the Automation job output, with no email service or Office 365 licence needed.

Authentication is handled entirely by a System-Assigned Managed Identity — zero credentials stored anywhere.

⚙️Azure Automation
Runbook
PowerShell 7.2
MSI Token
🔑Managed Identity
(System-Assigned)
No secrets needed
Bearer Token
📊Microsoft Graph
API
/v1.0/applications
Results
🖥️Console
Output
Job Logs
ComponentPurposeCost
Azure Automation AccountHosts and schedules the RunbookFree (500 min/month)
System-Assigned Managed IdentityAuthenticates to Graph API — no credentials storedFree
Microsoft Graph APIReads all App Registration credential metadataFree

Prerequisites

  • An active Azure subscription
  • Global Administrator or Privileged Role Administrator in Azure AD
  • Access to Azure Cloud Shell (used for the permission assignment)
  • PowerShell 5.1+ or PowerShell 7 (Runbook runtime)
💡

No Office 365 licence required. Results are written to the Automation job console only — no email, no Exchange, no licensed mailbox needed.

Create the Azure Automation Account

Skip this step if you already have an Automation Account.

1

Navigate to Automation Accounts

In the Azure Portal search bar type Automation Accounts and open the service.

2

Click + Create

Choose your Subscription, Resource Group, give it a name (e.g. automatewithravi), pick a Region and click Review + Create.

Enable System-Assigned Managed Identity

Enable the Managed Identity so the Runbook can authenticate to Microsoft Graph without storing any credentials.

1

Open your Automation Account → Identity

In the left menu under Account Settings, click Identity.

2

Toggle Status to On and Save

On the System assigned tab, toggle Status to On, click Save and confirm.

3

Copy the Object (principal) ID

After saving, the Object (principal) ID GUID appears. Copy it — you need it in Step 3.

Azure Portal — automatewithravi | Identity
automatewithravi
Automation Account
⚙️ Overview
📋 Activity log
🔒 Access control (IAM)
🏷️ Tags
📖 Process Automation
Account Settings
⚙️ Properties
🌐 Networking
🔑 Keys
💰 Pricing
🔐 Identity
System assigned
User assigned

A system assigned managed identity is restricted to one per resource and is tied to the lifecycle of this resource. The identity is deleted when this resource is deleted. You can grant permissions for the managed identity using Azure role-based access control (RBAC). The managed identity is authenticated with Azure Active Directory (AD), so you don't have to store any credentials in code.

💾 Save
✕ Discard
🔄 Refresh
Status ⓘ
Off
On
Object (principal) ID ⓘ
████████████████████████████████████████
Permissions ⓘ
Azure role assignments
ℹ️ This resource is registered with Microsoft Entra ID. The managed identity can be granted permissions to access Azure services without needing credentials in code.

Copy the Object (principal) ID from this page — you will paste it as $MI_OBJECT_ID in Step 3.

Assign the Graph API Permission

The Managed Identity needs the Application.Read.All Microsoft Graph application role. The Azure Portal UI does not support this assignment for managed identities — use Azure Cloud Shell instead.

⚠️

Global Administrator or Privileged Role Administrator required to run these commands.

Azure Cloud Shell — PowerShell

Azure Cloud Shell — PowerShell
# Replace with your Managed Identity Object ID (copied from Step 2)
$MI_OBJECT_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Microsoft Graph app ID (same in every tenant)
$GRAPH_APP_ID = "00000003-0000-0000-c000-000000000000"

# Get the Graph service principal in your tenant
$graphSp = Get-AzADServicePrincipal -ApplicationId $GRAPH_APP_ID

# Find the Application.Read.All role definition ID
$roleId = ($graphSp.AppRole |
           Where-Object { $_.Value -eq "Application.Read.All" }).Id

# Assign the role to the Managed Identity
New-AzADServicePrincipalAppRoleAssignment `
    -ServicePrincipalId $MI_OBJECT_ID `
    -PrincipalId        $MI_OBJECT_ID `
    -ResourceId         $graphSp.Id `
    -AppRoleId          $roleId

Write-Host "Application.Read.All assigned successfully." -ForegroundColor Green

Azure Cloud Shell — Bash / CLI (alternative)

Azure Cloud Shell — Bash
# Replace with your Managed Identity Object ID
MI_OBJECT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

GRAPH_SP_ID=$(az ad sp show --id 00000003-0000-0000-c000-000000000000 --query id -o tsv)
ROLE_ID=$(az ad sp show --id 00000003-0000-0000-c000-000000000000 \
          --query "appRoles[?value=='Application.Read.All'].id" -o tsv)

az rest --method POST \
  --uri "https://graph.microsoft.com/v1.0/servicePrincipals/$MI_OBJECT_ID/appRoleAssignments" \
  --body "{\"principalId\":\"$MI_OBJECT_ID\",\"resourceId\":\"$GRAPH_SP_ID\",\"appRoleId\":\"$ROLE_ID\"}"

echo "Done."

Verify Permission via Cloud Shell

Run the following command in Azure Cloud Shell to confirm the role was assigned correctly. This is the most reliable way to verify — quicker and more accurate than the Portal UI.

Azure Cloud Shell — PowerShell
# Replace with your Managed Identity Object ID
$MI_OBJECT_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

$assignments = Get-AzADServicePrincipalAppRoleAssignment -ServicePrincipalId $MI_OBJECT_ID

foreach ($a in $assignments) {
    $sp   = Get-AzADServicePrincipal -ObjectId $a.ResourceId
    $role = $sp.AppRole | Where-Object { $_.Id -eq $a.AppRoleId }
    [PSCustomObject]@{
        Resource   = $sp.DisplayName
        Permission = $role.Value
        AssignedOn = $a.CreatedAt
    }
} | Format-Table -AutoSize
Cloud Shell — Expected Output
Resource           Permission            AssignedOn
--------           ----------            ----------
Microsoft Graph    Application.Read.All   08/03/2026 14:00:00

If you see Application.Read.All under Microsoft Graph the permission is correctly assigned and you can proceed to Step 5.

Create & Publish the Runbook

1

Open Runbooks

In your Automation Account, click Runbooks+ Create a runbook.

2

Configure

Name: Automatewithravi_App-registration  ·  Type: PowerShell  ·  Runtime: 7.2. Click Create.

3

Paste the script

Clear the editor, paste the script from Full Script below (or view it on GitHub), and click Save.

4

Publish

Click Publish and confirm. The Runbook is now ready to run.

Run & Review Console Output

1

Start the Runbook

Click Start. In the parameters dialog set ExpiryThresholdDays to 30 (or your preferred value) and click OK.

2

Open the Output tab

Wait for Status: Completed, then click the Output tab to see results.

Azure Portal — Automatewithravi_App-registration Job Output
Home > Automatewithravi_App-registration (automatewithravi/Automatewithravi_App-registration)
Automatewithravi_App-registration 3/8/2026, 14:41
Job
▶ Resume⬛ Stop⏸ Suspend👤 Feedback 🔄 Refresh↑ Export output
∧ Essentials
Id
e3485245-96f4-43c6-83fc-ed691bfcbbea
Status
Completed
Ran on
Azure
Ran As
User
Input
Output
Errors
Warnings
All Logs
Exception
AppDisplayName        Type    CredentialName     ExpiryDate    Status       DaysLeft
--------------        ----    --------------     ----------    ------       --------
PowerShell_Connecti...  Secret  New_secret         21 Mar 2026   EXPIRING     13

13

The job completed successfully. PowerShell_Connecti... has a secret New_secret expiring on 21 Mar 2026 — 13 days away. Rotate it before it expires to avoid service interruption.

Schedule the Runbook

1

Open Schedules

From your Runbook, click Schedules+ Add a schedule.

2

Create a schedule

Name it (e.g. weekly-monday-9am), set recurrence to Weekly, day to Monday, time to 09:00.

3

Set parameters & Save

Click Configure parameters, set ExpiryThresholdDays to 30, click OK then OK again to save.

💡

View past scan results anytime under Automation Account → Jobs. Every job run preserves the full output log.

Full Script Reference

The complete script is hosted on GitHub. Click the button below to view, copy, or download the .ps1 file directly from the repository.

Azure Automation PowerShell 7.2 Microsoft Graph Managed Identity No secrets No O365 licence
View Full Script on GitHub