To run the audit
Read scopes
Your own account, on Graph.
-
Application.Read.All— Graph, delegated -
AuditLog.Read.All— Graph, delegated -
Directory.Read.All— Graph, delegated
AppLifecycleAnalyzer
Three delegated scopes on Microsoft Graph, and nothing in Azure. Reading and acting are two different sets of rights, and the script only ever does the first.
Microsoft.Graph.Authentication and Microsoft.Graph.Applications — offered on first run, or -AutoInstallModulesTo run the audit
Your own account, on Graph.
Application.Read.All — Graph, delegatedAuditLog.Read.All — Graph, delegatedDirectory.Read.All — Graph, delegatedTo act on a finding
Your own account, and only with -RequestWriteScopes.
Application.ReadWrite.All — Graph, delegatedTwo ways to end up with a tenant that looks entirely dormant. Without AuditLog.Read.All every app comes back with no recorded sign-in — and without a premium tier the same happens, because servicePrincipalSignInActivities needs one. In that case the report still lists every app and its credentials, and the activity column says it does not know rather than guessing.
It reports registrations. It does not know what depends on them. An expired secret can sit next to a certificate that is doing all the work, and a dormant app can be the one that runs every December.
| Do not use for | Why | Do this instead |
|---|---|---|
| Managed identities | Different lifecycle, no credentials to expire | Look at their role assignments instead |
| Deciding on its own that an app is dead | No sign-in is evidence of nothing running, not of nothing needing it | Ask the owner, then delete |
| Continuous monitoring | One run is one point in time | Entra ID Protection, Defender for Cloud Apps, Sentinel |
| Compliance baselines | It has no baseline to compare against | Maester, ScubaGear |
| Unattended cleanup | Every command is meant to pass a person first | Access reviews, or your own change process |