Removing the Relay

When you stop using Calibrant — or you just want the relay gone — this page removes every trace of it from your Azure subscription and your Microsoft 365 tenant. Most of the time is spent waiting for Azure to delete the VM; timing varies by region and service availability.

The short version is delete the resource group. That removes the VM and the Managed Identity, and the Managed Identity is what held all the permissions. The rest of this page is the parts that are not obvious.

Three things worth knowing first

Deleting the VM is not enough. The relay uses a user-assignedManaged Identity, and Microsoft is explicit that its lifecycle is decoupled from the resources it is attached to: "You need to manually delete a user-assigned identity when it is no longer required, even if no resources are associated with it." Delete only the VM and the identity survives, still holding every permission it was granted — including, if you enabled it, the write-capable Power Platform registration — with nothing running on it and nobody watching it. Delete the resource group, which contains both.

Access does not stop the instant you delete. Tokens issued before deletion stay valid until they expire, and Azure caches Managed Identity tokens for roughly 24 hours. Some Microsoft endpoints re-check the directory and start failing immediately; others honour the token until it expires. If you need access to stop at a specific moment — during an incident, say — delete the resource group and then treat the following 24 hours as a wind-down window rather than a hard cutoff.

The identity stays visible for 30 days. Microsoft soft-deletes Managed Identities, and "you can view the soft deleted managed identity service principal, but you cannot restore or permanently delete it." Seeing it in Entra ID after you delete it is expected and does not mean the deletion failed. It holds no permissions in that state, and you cannot purge it early.

Step 1 — See what the relay identity currently holds

Before changing anything, get a baseline. This script only reads — it requests read-only Graph scopes and issues no writes, so it is safe to run against production without thinking about it. Global Reader is enough; you do not need Global Administrator.

↓ Download check-relay-permissions.ps1

# In a pwsh 7 terminal on your own machine (not the VM):
./check-relay-permissions.ps1

It prints the tenant it connected to, then every application permission, directory role, and group membership the identity holds. On a relay granted by the current script expect 19 application permissions, 1 directory role (Global Reader), and — if you enabled the Fabric checks — 1 group. Relays granted before August 2026 will also show legacy Graph roles and up to five legacy directory roles; the script flags those as removable. It exits 0 when the identity holds nothing and 1 when anything remains, so you can use it as a gate in your own offboarding checklist.

Read the tenant banner. A clean report against the wrong tenant looks exactly like a clean report against the right one. The script prints the tenant domain, tenant ID, and signed-in account before anything else — check them. If your admin account can reach more than one tenant, pass -TenantId so there is no ambiguity at all.

If you deployed with different names, see Customising the check script below.

Step 2 — Delete the Azure resources

This deletes the VM, the Managed Identity, the virtual network, the NSG, and the Log Analytics workspace in one operation, and it is the step that actually removes the relay's access to your tenant.

az group delete --name calibrant-relay-rg --yes

# If you deployed to a different resource group, list them first:
az group list --query "[?contains(name,'calibrant')].name" -o tsv

Deletion takes a few minutes. If you would rather keep the VM — to redeploy later without paying to rebuild it — delete just the identity instead. The relay stops working immediately, and the VM sits there with no access to anything:

az identity delete --name calibrant-relay-identity --resource-group calibrant-relay-rg

Step 3 — Clean up what Azure cannot reach

Three things live outside Azure and outside Entra ID, so deleting the resource group does not touch them. Two are tenant settings you changed for Calibrant and would otherwise stay changed.

Fabric admin portal settings

During setup you enabled two service principal settings in the Fabric admin portal, each scoped to a security group. Both stay enabled after the relay is gone. Turn them off if nothing else uses them:

  1. Developer settings > Service principals can call Fabric public APIs
  2. Admin API settings > Service principals can access read-only admin APIs

Then delete the security group you created for this (commonly named FabricApiAccess) if it exists only for Calibrant. It will be empty once the identity is deleted, but an empty group left in an allowlist is a trap for whoever finds it later.

Power Platform management application

The relay was registered with Power Platform so it could read DLP policies and environments. That registration lives in Power Platform, keyed by the identity's application (client) ID — not in Entra ID, so it does not appear in any directory role listing and deleting the resource group does not remove it.

Remove this one even if you are keeping the relay. It is the only credential Calibrant asks for that is not read-only — the Power Platform admin API it authorises includes write operations such as deleting an environment, and Microsoft offers no reader variant. If you decided not to enable the Power Platform checks, or you have changed your mind since setup, this command is how you take it back. The only consequence is that those checks report not evaluated.

Run the check script to see whether it is still listed in your tenant; if it is, remove it:

$t = az account get-access-token --resource https://api.bap.microsoft.com/ --query accessToken -o tsv

Invoke-RestMethod -Method DELETE -Headers @{ Authorization = "Bearer $t" } `
  -Uri 'https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/adminApplications/<client-id>?api-version=2020-10-01'

You need the client ID for this, so capture it before you delete the resource group — it is much harder to find afterwards:

az identity show --name calibrant-relay-identity --resource-group calibrant-relay-rg --query clientId -o tsv

Directory roles

Global Reader — and on older relays the legacy Exchange, Teams, SharePoint, Power Platform and Fabric Administrator roles — are directory role memberships held by the identity, so they go when the identity does. Nothing to do here, but Step 5 verifies it rather than assuming it.

Step 4 — Remove the relay from Calibrant

Go to Connections, find the relay under Calibrant Relay, and delete it. This invalidates its API key, so even a VM you kept can no longer reach Calibrant.

If you are leaving entirely, go to Settings and request account deletion. Calibrant begins the checked deletion immediately: it cancels the linked subscription, removes the live workspace data and relay credential hashes, and removes the workspace members' Calibrant sign-in accounts. Calibrant does not retain a customer Microsoft OAuth token and does not offer a 30-day undo window. Provider-managed backup copies age out under the backup-retention window. See the privacy policy for what is kept and for how long.

Step 5 — Verify

Run the check script again. Do not skip this because the deletion appeared to succeed — confirming it is the entire point, and it takes fifteen seconds.

./check-relay-permissions.ps1 -ApplicationId <client-id>

Expect:

  • Not found in this tenant — or a [SOFT-DELETED] note, which is fine
  • Resource group not found
  • Power Platform: Not registered
  • CLEAR - this identity holds no access, and exit code 0

Anything reported as [HELD] is still live. Re-run the relevant step above.

Customising the check script

The defaults match what the Bicep template creates. If you renamed anything, deployed more than one relay, or administer several tenants, pass the parameters below. Every one of them is optional.

ParameterWhen you need itHow to find the value
-DisplayNameYou gave the Managed Identity a name other than calibrant-relay-identityaz identity list --query "[].name" -o tsv
-ServicePrincipalIdSeveral identities share a display name, or you want zero ambiguity. Overrides -DisplayNameaz identity show -n <name> -g <rg> --query principalId -o tsv
-ApplicationIdChecking the Power Platform registration, or the identity is already deleted and this is the only handle leftaz identity show -n <name> -g <rg> --query clientId -o tsv
-TenantIdYour admin account can reach more than one tenant. Strongly recommended for partners and MSPsaz account show --query tenantId -o tsv
-SubscriptionIdThe relay is not in the subscription your Azure CLI currently points ataz account list --query "[].{name:name, id:id}" -o table
-ResourceGroupNameYou deployed somewhere other than calibrant-relay-rgaz group list --query "[].name" -o tsv
-SkipAzureCheckYou have Graph access but no Azure CLI, or no rights to the subscription
-SkipPowerPlatformCheckYou never used the Power Platform checks
-JsonChecking many tenants and collecting results

A fully specified run looks like this:

./check-relay-permissions.ps1 `
  -TenantId contoso.onmicrosoft.com `
  -DisplayName 'contoso-relay-mi' `
  -ResourceGroupName 'rg-calibrant-prod' `
  -SubscriptionId 00000000-0000-0000-0000-000000000000 `
  -ApplicationId 11111111-1111-1111-1111-111111111111

And across many tenants, collecting the results:

$tenants = @('contoso.onmicrosoft.com','fabrikam.onmicrosoft.com')

$tenants | ForEach-Object {
    ./check-relay-permissions.ps1 -TenantId $_ -Json | ConvertFrom-Json
} | Select-Object tenantDomain, identityFound, holdsNothing | Format-Table

Verifying the script before you run it

It is a PowerShell script downloaded over the internet, so treat it like one. It requests only Directory.Read.All and Application.Read.All and contains no write operations — you can confirm both by reading it, and by comparing your download against the copy in our public repository:

Published digest — generated at build time from the exact file this site serves, so it cannot drift.
SHA-256: 8eba3357 30a5808d 0204197f 53180428 6430ef33 c2040a38 c6374adf e0a5006b
# Windows
Get-FileHash .\check-relay-permissions.ps1 -Algorithm SHA256

# Mac / Linux
shasum -a 256 check-relay-permissions.ps1

The digest and the file come from the same origin, so this catches a corrupted or modified download rather than serving as independent attestation. The script only reads — you can confirm that by searching it for Remove-, Set-, or New- and finding none.

What Calibrant keeps

Removing the relay stops all collection. It does not delete scan history already stored in Calibrant — that follows the retention policy, and you can delete individual scans from the results pages or request full account deletion in Settings. See the privacy policy for retention windows by plan.