Remove-ElevatedAccess-Automation.ps1
<#PSScriptInfo
.VERSION 1.0.0 .GUID bea7afb9-c39a-42b0-9e88-76fc7c026b9a .AUTHOR Sebastian Flæng Markdanner .COMPANYNAME Cloudy With a Chance of Security .COPYRIGHT (c) 2025 Cloudy With a Chance of Security. All rights reserved. .TAGS Azure, Automation, Entra, Elevated Access, Managed Identity .LICENSEURI https://opensource.org/licenses/MIT .PROJECTURI https://chanceofsecurity.com/ .EXTERNALMODULEDEPENDENCIES Az.Accounts .RELEASENOTES Initial release of the script to remove Microsoft Entra Elevated Access using Azure Automation Account with Managed Identity. .PRIVATEDATA #> <# .SYNOPSIS Removes Microsoft Entra Elevated Access (User Access Administrator role) from a user using Azure Automation Account with Managed Identity. .DESCRIPTION This script is designed to run in an Azure Automation account and be triggered by a Logic App. It uses the System Assigned Managed Identity of the Automation Account to authenticate to Azure. The script removes Elevated Access in Entra by removing the User Access Administrator role assignment at the root scope ("/") for the specified user. The script provides structured output that can be consumed by the calling Logic App. .PARAMETER UserId Required. The Object ID of the user whose elevated access should be removed. The script automatically converts User Principal Names (email addresses) to Object IDs. .NOTES Author: Sebastian Flæng Markdanner (Modified for Azure Automation) Website: https://chanceofsecurity.com Version: 2.0 Last Updated: 2025-02-18 License: MIT LicenseUri: https://opensource.org/licenses/MIT ProjectUri: https://chanceofsecurity.com Requirements: - Azure Automation Account with System Assigned Managed Identity - The Managed Identity must have appropriate permissions (Global Administrator or User Access Administrator) @ root - Az modules imported in the Automation Account #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$UserId ) # Add timestamp function function Get-Timestamp { return "[{0:yyyy-MM-dd HH:mm:ss}]" -f (Get-Date) } # Initialize output object for Logic App $outputObject = [PSCustomObject]@{ Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") Action = "Remove Elevated Access" UserId = $UserId Status = "Started" Message = "Initializing removal process" RoleAssignmentId = "" Success = $false } try { # Connect using the Automation Account's Managed Identity Write-Output "Connecting to Azure using Managed Identity..." Connect-AzAccount -Identity # Define API URLs and versions $managementApi = "https://management.azure.com" $apiVersion = "2022-04-01" $roleDefinitionApi = "$managementApi/providers/Microsoft.Authorization/roleDefinitions?api-version=$apiVersion&`$filter=roleName+eq+'User Access Administrator'" # Get access token for Azure Management API $accessTokenARM = (Get-AzAccessToken -ResourceUrl $managementApi).Token # Set request headers for Azure ARM API calls $headersARM = @{ "Authorization" = "Bearer $accessTokenARM" "Content-Type" = "application/json" } # Step 1: Get User Access Administrator Role Definition ID Write-Output "Retrieving User Access Administrator role definition..." $roleResponse = Invoke-RestMethod -Uri $roleDefinitionApi -Method Get -Headers $headersARM $roleDefinitionId = $roleResponse.value[0].id if (-not $roleDefinitionId) { throw "Failed to retrieve User Access Administrator Role Definition ID. Please ensure the Managed Identity has sufficient permissions." } Write-Output "Retrieved User Access Administrator Role ID: $roleDefinitionId" # Step 2: Convert UPN to Object ID if the provided UserId is an email/UPN if ($UserId -notmatch '^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$') { Write-Output "Converting user principal name to Object ID..." try { $objId = (Get-AzADUser -UserPrincipalName $UserId).Id if (-not $objId) { throw "Unable to find Object ID for user $UserId" } $UserId = $objId } catch { throw "Failed to retrieve Object ID for user $UserId. Error: $_" } } Write-Output "Using User Object ID: $UserId" $outputObject.UserId = $UserId # Step 3: Get Role Assignments for User at Root Scope using ARM API Write-Output "Searching for elevated access role assignments..." $roleAssignmentsApi = "$managementApi/providers/Microsoft.Authorization/roleAssignments?api-version=$apiVersion&`$filter=principalId+eq+'$UserId'" $roleAssignmentsResponse = Invoke-RestMethod -Uri $roleAssignmentsApi -Method Get -Headers $headersARM # Find role assignment for User Access Administrator at "/" scope $roleAssignment = $roleAssignmentsResponse.value | Where-Object { $_.properties.roleDefinitionId -eq $roleDefinitionId -and $_.properties.scope -eq "/" } if (-not $roleAssignment) { $outputObject.Status = "Completed" $outputObject.Message = "No elevated access role assignments found for removal. The user either doesn't have elevated access or it was already removed." $outputObject.Success = $true return $outputObject } $roleAssignmentId = $roleAssignment.name $outputObject.RoleAssignmentId = $roleAssignmentId Write-Output "Found Elevated Access Role Assignment ID: $roleAssignmentId" # Step 4: Remove Elevated Access $removeRoleApi = "$managementApi/providers/Microsoft.Authorization/roleAssignments/$($roleAssignmentId)?api-version=$apiVersion" Write-Output "Removing Elevated Access..." Invoke-RestMethod -Uri $removeRoleApi -Method Delete -Headers $headersARM | Out-Null $outputObject.Status = "Completed" $outputObject.Message = "Successfully removed Elevated Access for user" $outputObject.Success = $true Write-Output "$(Get-Timestamp) Successfully removed Elevated Access for user: $UserId" Write-Output "The user no longer has User Access Administrator privileges at the root scope." } catch { $errorMessage = "Failed to remove Elevated Access for user: $UserId. Error: $_" Write-Error $errorMessage $outputObject.Status = "Failed" $outputObject.Message = $errorMessage $outputObject.Success = $false } # Return structured output for Logic App consumption return $outputObject |