Public/Permissions/Invoke-365TuneRevokeAzure.ps1
|
function Invoke-365TuneRevokeAzure { <# .SYNOPSIS Revokes Reader permissions previously granted to the 365TUNE Enterprise App in Azure. .DESCRIPTION Removes Reader access from root scope "/" and AAD IAM scope "/providers/Microsoft.aadiam". Safe to re-run - exits cleanly if no assignments are found. Run from local PowerShell or Cloud Shell. Your account must have Global Administrator rights and "Access management for Azure resources" enabled in Entra ID > Properties. .EXAMPLE Invoke-365TuneRevokeAzure .NOTES Author : Metawise Consulting LLC Module : 365TUNE Version : 1.9.0 #> [CmdletBinding()] param( [switch]$SkipAuth ) $displayName = "365TUNE - Security and Compliance" Write-Host "`n======================================================" -ForegroundColor Cyan Write-Host " 365TUNE - Revoke Azure Permissions" -ForegroundColor Cyan Write-Host "======================================================`n" -ForegroundColor Cyan # Step 1 - Check modules Write-Host "[1/5] Checking required modules..." -ForegroundColor Cyan foreach ($module in @("Az.Accounts", "Az.Resources")) { if (-not (Get-Module -ListAvailable -Name $module)) { Write-Host " Installing $module..." -ForegroundColor Yellow Install-Module -Name $module -Force -Scope CurrentUser } } Import-Module Az.Accounts, Az.Resources Write-Host " [OK] Modules ready." -ForegroundColor Green # Step 2 - Authenticate Write-Host "`n[2/5] Authenticating..." -ForegroundColor Cyan if (-not $SkipAuth) { $inCloudShell = ($env:ACC_CLOUD -eq "PROD") -or ($env:POWERSHELL_DISTRIBUTION_CHANNEL -like "*CloudShell*") -or ($env:AZUREPS_HOST_ENVIRONMENT -like "*cloud-shell*") if ($inCloudShell) { Connect-AzAccount -Identity -WarningAction SilentlyContinue | Out-Null } else { Disconnect-AzAccount -ErrorAction SilentlyContinue | Out-Null Connect-AzAccount -WarningAction SilentlyContinue | Out-Null } } $context = Get-AzContext if (-not $context) { throw "Not authenticated. Run without -SkipAuth or log in manually first." } Write-Host " Tenant : $($context.Tenant.Id)" -ForegroundColor Gray Write-Host " Account : $($context.Account.Id)" -ForegroundColor Gray Write-Host " [OK] Authenticated." -ForegroundColor Green # Step 3 - Fetch Service Principal Write-Host "`n[3/5] Looking up 365TUNE Service Principal..." -ForegroundColor Cyan $sp = Get-AzADServicePrincipal -DisplayName $displayName | Select-Object Id, AppId, DisplayName if (-not $sp) { throw "Service Principal '$displayName' not found in this tenant." } $servicePrincipalId = $sp.Id Write-Host " Object ID : $servicePrincipalId" # Step 4 - Pre-flight check Write-Host "`n[4/5] Checking for existing assignments..." -ForegroundColor Cyan $existing = Invoke-AzRestMethod ` -Path "providers/Microsoft.aadiam/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01" ` -Method GET $existingValues = ($existing.Content | ConvertFrom-Json).value | Where-Object { $_.properties.principalId -eq $servicePrincipalId } if ($existingValues.Count -eq 0) { Write-Host "`n======================================================" -ForegroundColor Cyan Write-Host " No assignments found - nothing to revoke. [OK]" -ForegroundColor Green Write-Host "======================================================`n" -ForegroundColor Cyan return } Write-Host " Found $($existingValues.Count) assignment(s) - proceeding with removal." -ForegroundColor Yellow # Step 5 - Elevate and remove Write-Host "`n[5/5] Elevating and removing Reader permissions..." -ForegroundColor Cyan Invoke-365TuneElevation try { Remove-AzRoleAssignment ` -ObjectId $servicePrincipalId ` -Scope "/" ` -RoleDefinitionName "Reader" ` -SkipClientSideScopeValidation ` -ErrorAction Stop Write-Host " [OK] Reader removed from '/'" -ForegroundColor Green } catch { if ($_.Exception.Message -like "*does not exist*" -or $_.Exception.Message -like "*NotFound*" -or $_.Exception.Message -like "*does not map*" -or $_.Exception.Message -like "*Forbidden*") { Write-Warning " [WARN] Reader at '/' not found - already removed" } else { throw } } $aadIamValues = $existingValues | Where-Object { $_.properties.scope -eq "/providers/Microsoft.aadiam" } if ($aadIamValues) { foreach ($assignment in $aadIamValues) { $del = Invoke-AzRestMethod ` -Path "providers/Microsoft.aadiam/providers/Microsoft.Authorization/roleAssignments/$($assignment.name)?api-version=2022-04-01" ` -Method DELETE if ($del.StatusCode -in @(200, 204)) { Write-Host " [OK] Reader removed from '/providers/Microsoft.aadiam'" -ForegroundColor Green } else { Write-Warning " [WARN] aadiam removal returned status $($del.StatusCode)" } } } else { Write-Warning " [WARN] Reader at '/providers/Microsoft.aadiam' not found - already removed" } $remaining = Invoke-AzRestMethod ` -Path "providers/Microsoft.aadiam/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01" ` -Method GET $remainingValues = ($remaining.Content | ConvertFrom-Json).value | Where-Object { $_.properties.principalId -eq $servicePrincipalId } if ($remainingValues.Count -eq 0) { Write-Host " [OK] Verified - no assignments remain." -ForegroundColor Green } else { Write-Warning " [WARN] $($remainingValues.Count) assignment(s) still remain - check Azure Portal." } Remove-365TuneElevation Write-Host "`n======================================================" -ForegroundColor Cyan Write-Host " 365TUNE Azure permissions revoked. [OK]" -ForegroundColor Green Write-Host " Tenant : $($context.Tenant.Id)" -ForegroundColor Green Write-Host " Account : $($context.Account.Id)" -ForegroundColor Green Write-Host "======================================================`n" -ForegroundColor Cyan } |