Listen to this Post

Introduction:
Hidden security risks lurk in many Microsoft Entra ID tenants where retired applications and outdated access grants persist, often overlooked. IAM admins can address this by implementing an automated, script-based approach using PowerShell and the Microsoft Graph API, which revokes overprivileged permissions, removes stale user assignments, and sends notifications. This method provides an auditable, repeatable, and source‑controlled solution that significantly strengthens an organization’s security governance posture without the need for complex Logic Apps or additional infrastructure.
Learning Objectives:
- Automate Least‑Privilege Enforcement: Learn to systematically revoke both delegated (OAuth2) and application (app role) permissions granted to a service principal.
- Remediate Stale Access: Discover how to remove obsolete user assignments linked to enterprise applications, closing potential backdoors.
- Implement Revoke‑First Notification Workflows: Understand the logic behind a robust “revoke then notify” process that ensures permissions are removed before stakeholders are alerted, preventing partial rollbacks.
You Should Know:
- Automating Enterprise App Permission Revocation with Microsoft Graph PowerShell
A robust security governance program requires the ability to programmatically discover and revoke unnecessary API permissions. The following extended walkthrough demonstrates how to connect to Microsoft Graph, target a specific service principal, and remove all lingering permissions using a purpose‑built script.
Step‑by‑step guide explaining what this does and how to use it:
- Step 1: Prepare the Environment – Install the Microsoft Graph PowerShell SDK if not already available:
Install-Module Microsoft.Graph -Scope CurrentUser -Force
- Step 2: Establish Secure Authentication – Connect with sufficient privileges. The script requires at least a Cloud Application Administrator role and the
Application.ReadWrite.All,DelegatedPermissionGrant.ReadWrite.All, `AppRoleAssignment.ReadWrite.All` scopes to manage both delegated and application permissions.
Connect-MgGraph -Scopes "Application.ReadWrite.All", "DelegatedPermissionGrant.ReadWrite.All", "AppRoleAssignment.ReadWrite.All"
- Step 3: Target the Service Principal – Obtain the specific enterprise application (service principal) that requires cleanup.
$ServicePrincipalId = "00000000-0000-0000-0000-000000000000" Replace with actual SPN ID $sp = Get-MgServicePrincipal -ServicePrincipalId $ServicePrincipalId
- Step 4: Revoke All Delegated (OAuth2) Permissions – Retrieve all OAuth2 permission grants (delegated permissions) where the clientId matches the target app and delete them. This effectively removes user consent grants for the application.
$spOauth2PermissionsGrants = Get-MgOauth2PermissionGrant -Filter "clientId eq '$($sp.Id)'" -All
$spOauth2PermissionsGrants | ForEach-Object { Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId $_.Id }
- Step 5: Revoke All Application (App Role) Permissions – Retrieve and remove all app role assignments where the principal type is “ServicePrincipal” (application permissions). These grants allow the app to act with its own identity.
$spApplicationPermissions = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All | Where-Object { $<em>.PrincipalType -eq "ServicePrincipal" }
$spApplicationPermissions | ForEach-Object { Remove-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -AppRoleAssignmentId $</em>.Id }
- Step 6: Remove Stale User Assignments – Finally, eliminate any user assignments to the application’s roles. This clears the list under “Users and groups” in Entra ID.
$userAssignments = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All | Where-Object { $<em>.PrincipalType -eq "User" }
$userAssignments | ForEach-Object { Remove-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -AppRoleAssignmentId $</em>.Id }
Analysis: This automated approach eliminates manual, error‑prone portal work. By removing all permission types in a defined sequence and verifying each step, the script ensures a complete cleanup. Organisations can integrate this code into CI/CD pipelines, schedule it as an Azure Automation runbook, or run it on‑demand during regular access reviews. The “revoke‑first” workflow prevents any race condition where a user might still have access while a notification is being sent.
- Validating Revocation and Monitoring Entra ID Audit Logs
After revoking permissions, it is essential to confirm the changes and maintain an immutable record for compliance purposes. Microsoft Entra ID automatically logs all administrative actions, including permission grant deletions and role assignment removals.
Step‑by‑step guide explaining what this does and how to use it:
- Step 1: Query Audit Logs for Permission Deletions – Use `Get-MgAuditLogDirectoryAudit` to retrieve audit events related to the recent revocation activities. Filter by the affected service principal or the operation type “Delete OAuth2PermissionGrant”.
Get-MgAuditLogDirectoryAudit -Filter "activityDisplayName eq 'Delete OAuth2PermissionGrant'" -Top 10
- Step 2: Verify the Absence of Permissions – Re‑fetch the OAuth2 permission grants and app role assignments for the cleaned service principal. Both result sets should be empty, confirming successful revocation.
$checkOAuth = Get-MgOauth2PermissionGrant -Filter "clientId eq '$($sp.Id)'" -All $checkAppRole = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All Write-Host "Remaining OAuth grants: $($checkOAuth.Count)" Write-Host "Remaining app role assignments: $($checkAppRole.Count)"
- Step 3: Automate Notification of Cleanup – The original script can be extended to send email notifications (using
Send-MailMessage) to application owners and affected users after verification is complete. This ensures stakeholders are aware of the access removal, along with details such as tenant ID, timestamp, and the specific permissions revoked. -
Step 4: Schedule Regular Cleanups – Wrap the entire script in an Azure Automation runbook or a Windows Task Scheduler job to run weekly or monthly. Combine it with export of audit logs to a SIEM (e.g., Microsoft Sentinel) for ongoing compliance.
Analysis: Monitoring audit logs provides a tamper‑evident trail essential for compliance frameworks like ISO 27001, SOC 2, or PCI DSS. By integrating verification steps directly into the script, you create a self‑validating process that can be used as evidence during audits. Scheduling this routine moves security governance from a reactive, point‑in‑time exercise to a continuous, proactive discipline.
3. Hardening the Solution with Least‑Privilege Automation
The automation service principal used to run the cleanup script must itself be secured according to the principle of least privilege. Over‑permissioning the automation account could inadvertently introduce new risks.
Step‑by‑step guide explaining what this does and how to use it:
- Step 1: Create a Dedicated Automation App Registration – In the Microsoft Entra admin center, register a new application that will host the automation identity. Note its application (client) ID.
-
Step 2: Grant Only Required Graph Permissions – Instead of using a highly privileged user account, grant the automation app only the following Microsoft Graph application permissions (not delegated):
Application.ReadWrite.All,DelegatedPermissionGrant.ReadWrite.All, andAppRoleAssignment.ReadWrite.All. These three permissions are the minimum needed to revoke both OAuth2 grants and app role assignments. -
Step 3: Configure Certificate or Client Secret Authentication – For unattended script execution, use a certificate (recommended) or a client secret. Store the credential securely in Azure Key Vault and retrieve it at runtime.
$ClientId = "your-automation-app-id" $TenantId = "your-tenant-id" $ClientSecret = ConvertTo-SecureString "your-secret" -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential($ClientId, $ClientSecret) Connect-MgGraph -ClientCredential $Credential -TenantId $TenantId
- Step 4: Restrict the Automation’s Scope – Use administrative unit scope or conditional access policies to limit which service principals the automation can modify, if possible. Avoid granting `Directory.ReadWrite.All` or other highly privileged roles.
Analysis: Adhering to least privilege for the automation identity is critical. An automation account with excessive permissions could be a lucrative target for adversaries who discover its credentials. By using a dedicated app registration with minimal application permissions and rotating secrets or certificates regularly, the solution remains both effective and secure.
4. Troubleshooting Common Revocation Errors
During permission revocation, you may encounter errors that require specific handling. One frequent issue is a `400 BadRequest` with the message “Invalid resource identifier for EntitlementGrant” when using `Remove-MgServicePrincipalAppRoleAssignment` for certain app role assignments.
Step‑by‑step guide explaining what this does and how to use it:
- Step 1: Identify the Affected Assignment – Retrieve all app role assignments for the service principal and note which ones fail.
$spApplicationPermissions = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All
- Step 2: Use the Microsoft Graph API Endpoint Directly – If the PowerShell cmdlet fails, fall back to the raw REST API call. Replace the IDs with the appropriate values and use
Invoke-MgGraphRequest.
$uri = "https://graph.microsoft.com/v1.0/servicePrincipals/$ServicePrincipalId/appRoleAssignments/$appRoleAssignmentId" Invoke-MgGraphRequest -Method DELETE -Uri $uri
- Step 3: Implement Retry Logic – Build a retry loop that catches transient errors and attempts the deletion again after a short delay.
$maxRetries = 3
$retryDelay = 5
for ($i = 0; $i -lt $maxRetries; $i++) {
try {
Remove-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -AppRoleAssignmentId $assignment.Id -ErrorAction Stop
break
} catch {
if ($i -eq $maxRetries - 1) { throw }
Start-Sleep -Seconds $retryDelay
}
}
- Step 4: Handle “Not Found” Gracefully – When an assignment has already been deleted, the cmdlet may throw a
404 Not Found. Wrap the removal in a `try/catch` block and ignore that specific error, as the state is already clean.
Analysis: Proactively planning for revocation failures increases the reliability of the entire automation. The direct Graph API endpoint often succeeds when the higher‑level PowerShell cmdlet experiences issues. Implementing retries and ignoring “not found” errors makes the script resilient and suitable for unattended scheduling.
5. Integrating the Cleanup into a Compliance Pipeline
To achieve repeatable security governance, the permission revocation script should be integrated into a DevOps‑style compliance pipeline. This ensures that every decommissioned application is fully cleaned up before a release.
Step‑by‑step guide explaining what this does and how to use it:
- Step 1: Store the Script in Version Control – Commit the full PowerShell script to a Git repository (e.g., GitHub, Azure Repos). This provides change tracking and peer review capabilities.
-
Step 2: Create a Pipeline Step (Azure DevOps Example) – Add a PowerShell task to an Azure Pipeline that runs the script as part of an “Application Decommissioning” stage.
- task: PowerShell@2 inputs: filePath: '$(System.DefaultWorkingDirectory)/scripts/Revoke-AppPermissions.ps1' arguments: '-ServicePrincipalId $(ServicePrincipalId)' displayName: 'Revoke API Permissions and User Assignments'
- Step 3: Run Automated Tests Post‑Cleanup – After the revocation, execute a validation script that asserts no permissions remain. Fail the pipeline if the validation does not succeed.
if ((Get-MgOauth2PermissionGrant -Filter "clientId eq '$($sp.Id)'" -All).Count -gt 0) {
throw "Delegated permissions still exist after cleanup."
}
- Step 4: Archive Audit Logs as Build Artifacts – At the end of the pipeline, export the relevant audit logs and store them as pipeline artifacts for compliance evidence.
Analysis: Shifting security governance left into the development pipeline enforces consistent, auditable cleanup every time an application is retired. This approach not only reduces manual overhead but also provides immutable proof that security controls were applied, which is invaluable during internal or external audits.
What Undercode Say:
- Key Takeaway 1: Privilege revocation must be programmatic, auditable, and source‑controlled. Manual portal cleanup is error‑prone and unsustainable at scale. By using PowerShell and Microsoft Graph, you turn a risky chore into a reliable engineering process.
-
Key Takeaway 2: A “revoke‑then‑notify” sequence closes race conditions where a user could retain access after a notification email is sent. This small change in workflow order dramatically reduces the chance of leaving orphaned permissions.
Analysis: Overprivileged applications represent a significant yet often overlooked attack surface in Entra ID tenants. Stale API permissions can allow obsolete applications to continue accessing sensitive data long after they are no longer needed. The provided script addresses both delegated and application permissions comprehensively, removing user assignments as well. From a security perspective, this closes multiple potential backdoors in one action. Operationally, it reduces the number of objects in the tenant, simplifying future audits. The ability to run this script on a schedule or as part of a CI/CD pipeline moves security governance from a reactive, periodic task to a continuous, proactive discipline. In practice, implementing this automation can reduce the mean time to remediate overprivileged apps from days to minutes, directly improving the tenant’s overall security score.
Prediction:
- +1 Adoption of infrastructure‑as‑code practices for identity governance will accelerate, with organisations embedding permission revocation scripts directly into Terraform and ARM templates. This will lead to a measurable reduction in the average number of unused permissions per application.
-
-1 Attackers will increasingly target automation service principals used for permission revocation, attempting to steal their credentials and use the very same Graph permissions to grant themselves elevated access. Organisations that neglect least‑privilege for automation accounts will face severe breaches.
🎯Let’s Practice For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
IT/Security Reporter URL:
Reported By: David Alonso – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


