Public/Permissions/Invoke-365TUNERevokeAll.ps1
|
function Invoke-365TUNERevokeAll { <# .SYNOPSIS Revokes all 365TUNE permissions - Azure and Exchange Online in one step. .DESCRIPTION Works in both local PowerShell and Azure Cloud Shell. - Local PowerShell : Logs in once, no subscription picker, auto-selects home tenant, then runs RevokeExchange and RevokeAzure in sequence. - Cloud Shell : Authenticates as the current user (browser session). Exchange is revoked first (best practice - remove app-level access before RBAC). Azure revoke proceeds even if Exchange revoke fails. Your account must have Global Administrator and Exchange Administrator rights. .EXAMPLE Invoke-365TUNERevokeAll .NOTES Author : Metawise Consulting LLC Module : 365TUNE Version : 2.3.4 #> [CmdletBinding()] param() Write-Host "`n======================================================" -ForegroundColor Cyan Write-Host " 365TUNE - Full Permissions Revoke" -ForegroundColor Cyan Write-Host " Revoking Azure + Exchange Online in one step" -ForegroundColor Cyan Write-Host "======================================================`n" -ForegroundColor Cyan # Authenticate - Cloud Shell uses browser session, local PowerShell uses interactive login Write-Host "Authenticating..." -ForegroundColor Cyan $inCloudShell = ($env:ACC_CLOUD -eq "PROD") -or ($env:POWERSHELL_DISTRIBUTION_CHANNEL -like "*CloudShell*") -or ($env:AZUREPS_HOST_ENVIRONMENT -like "*cloud-shell*") if ($inCloudShell) { # Cloud Shell always has MSI loaded; the portal also injects the user's context. # Switch to the first non-MSI context if available, otherwise try interactive login. $context = Get-AzContext if (-not $context -or $context.Account.Type -eq 'ManagedService') { $userContext = Get-AzContext -ListAvailable | Where-Object { $_.Account.Type -ne 'ManagedService' } | Select-Object -First 1 if ($userContext) { Write-Host " Switching to user context..." -ForegroundColor Yellow Set-AzContext -Context $userContext | Out-Null } else { # az CLI in Cloud Shell is always authenticated as the portal user. Write-Host " Bridging from Azure CLI session..." -ForegroundColor Yellow try { $armToken = az account get-access-token --resource https://management.azure.com --query accessToken -o tsv 2>$null $graphToken = az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv 2>$null $tenantId = az account show --query tenantId -o tsv 2>$null $accountId = az account show --query user.name -o tsv 2>$null if ($armToken -and $tenantId -and $accountId) { Connect-AzAccount -AccessToken $armToken -GraphAccessToken $graphToken -TenantId $tenantId -AccountId $accountId -WarningAction SilentlyContinue | Out-Null } } catch { Write-Verbose "Azure CLI bridge failed: $_" } } $context = Get-AzContext } if (-not $context) { throw "No active Azure session in Cloud Shell. Reopen Cloud Shell from the Azure Portal and try again." } if ($context.Account.Type -eq 'ManagedService') { throw "Cloud Shell is authenticated as Managed Service Identity (MSI). Reopen Cloud Shell from the Azure Portal to restore your user session, then re-run." } } else { Disconnect-AzAccount -ErrorAction SilentlyContinue | Out-Null Connect-AzAccount -WarningAction SilentlyContinue -SkipContextPopulation | Out-Null $context = Get-AzContext if (-not $context) { throw "Authentication failed. Please try again." } # Auto-switch to home tenant - no subscription picker $allTenants = Get-AzTenant $userDomain = $context.Account.Id.Split("@")[1] $homeTenant = $allTenants | Where-Object { $_.Domains -contains $userDomain } | Select-Object -First 1 if (-not $homeTenant) { throw "Could not identify home tenant for '$($context.Account.Id)'." } Set-AzContext -TenantId $homeTenant.Id -WarningAction SilentlyContinue | Out-Null $context = Get-AzContext # refresh after tenant switch if (-not $context) { throw "Could not connect to home tenant. Please try again." } } Write-Host " Tenant : $($context.Tenant.Id)" -ForegroundColor Gray Write-Host " Account : $($context.Account.Id)" -ForegroundColor Gray Write-Host " [OK] Authenticated.`n" -ForegroundColor Green # Step 1 - Exchange first Write-Host "[ STEP 1 OF 3 ] Exchange Online Permissions" -ForegroundColor Magenta Write-Host "------------------------------------------------------" -ForegroundColor Magenta try { Invoke-365TuneRevokeExchange -SkipAuth } catch { Write-Host "`n[FAIL] Exchange revoke failed: $($_.Exception.Message)" -ForegroundColor Red Write-Host " Azure revoke will still proceed." -ForegroundColor Yellow Write-Host " Fix Exchange errors and re-run Invoke-365TuneRevokeExchange if needed." -ForegroundColor Yellow } # Allow Exchange output to flush (Cloud Shell buffer fix) Start-Sleep -Milliseconds 500 # Step 2 - Teams Write-Host "[ STEP 2 OF 3 ] Teams Permissions" -ForegroundColor Magenta Write-Host "------------------------------------------------------" -ForegroundColor Magenta try { Invoke-365TuneRevokeTeams -SkipAuth } catch { Write-Host "`n[FAIL] Teams revoke failed: $($_.Exception.Message)" -ForegroundColor Red Write-Host " Azure revoke will still proceed." -ForegroundColor Yellow Write-Host " Fix Teams errors and re-run Invoke-365TuneRevokeTeams if needed." -ForegroundColor Yellow } # Step 3 - Azure Write-Host "[ STEP 3 OF 3 ] Azure Permissions" -ForegroundColor Magenta Write-Host "------------------------------------------------------" -ForegroundColor Magenta try { Invoke-365TuneRevokeAzure -SkipAuth } catch { Write-Host "`n[FAIL] Azure revoke failed: $($_.Exception.Message)" -ForegroundColor Red Write-Host " Fix Azure errors and re-run Invoke-365TuneRevokeAzure." -ForegroundColor Yellow return } Write-Host "`n======================================================" -ForegroundColor Cyan Write-Host " 365TUNE permissions fully revoked. [OK]" -ForegroundColor Green Write-Host " [OK] Exchange: View-Only Configuration role removed" -ForegroundColor Green Write-Host " [OK] Teams : Teams Reader role removed" -ForegroundColor Green Write-Host " [OK] Azure : Reader removed from / and /providers/Microsoft.aadiam" -ForegroundColor Green Write-Host "======================================================`n" -ForegroundColor Cyan } |