<# .SYNOPSIS Prepare a Microsoft Entra tenant for Icon Map for Fabric: create the local record of the Microsoft services Icon Map reads data through. .DESCRIPTION Microsoft Entra will only let an application be consented for a Microsoft service once that service has a "service principal" (an enterprise application entry) in your tenant. Entra creates that entry the first time ANY third-party application is consented for the service - but it cannot create it as part of that same consent, so in a tenant that has never used the service the consent fails with: AADSTS650052: The app is trying to access a service ''(Azure Storage) that your organization '' lacks a service principal for. Fabric does not create these entries either. This script creates them. They carry no credentials, grant no access, and are the same objects Entra would have created silently the first time another app used the service. Always created: Azure Storage e406a681-f3d4-42a8-90b6-c2b029497af1 Lakehouse tables and files (OneLake) With -IncludeEventhouse: Azure Data Explorer 2746ea77-4702-4b45-80ca-3c97e680e8b7 Eventhouse / KQL databases Requires the Cloud Application Administrator, Application Administrator or Global Administrator role in the tenant, and the Azure CLI (`az`). Azure Cloud Shell has everything installed: https://shell.azure.com Idempotent: re-running reports the entries as already present. .PARAMETER TenantId The tenant to prepare. Omit to use the tenant `az` is already signed in to. .PARAMETER IncludeEventhouse Also create the Azure Data Explorer entry, for Eventhouse / KQL sources. .PARAMETER SkipLogin Use the current `az` session instead of signing in to -TenantId. .EXAMPLE ./Prepare-IconMapTenant.ps1 -TenantId 00000000-0000-0000-0000-000000000000 ./Prepare-IconMapTenant.ps1 -TenantId 00000000-0000-0000-0000-000000000000 -IncludeEventhouse -WhatIf #> [CmdletBinding(SupportsShouldProcess = $true)] param ( [string]$TenantId, [switch]$IncludeEventhouse, [switch]$SkipLogin ) $ErrorActionPreference = "Stop" $services = @( @{ Name = "Azure Storage"; AppId = "e406a681-f3d4-42a8-90b6-c2b029497af1"; Why = "Lakehouse tables and files (OneLake)" } ) if ($IncludeEventhouse) { $services += @{ Name = "Azure Data Explorer"; AppId = "2746ea77-4702-4b45-80ca-3c97e680e8b7"; Why = "Eventhouse / KQL databases" } } if (-not (Get-Command az -ErrorAction SilentlyContinue)) { throw "The Azure CLI (az) is not installed. Run this in Azure Cloud Shell (https://shell.azure.com) or install it from https://aka.ms/installazurecli." } if (-not $SkipLogin -and $TenantId) { Write-Host "Signing in to tenant $TenantId ..." az login --tenant $TenantId --allow-no-subscriptions --only-show-errors | Out-Null if ($LASTEXITCODE -ne 0) { throw "az login failed." } } $tenantNow = az account show --query tenantId -o tsv 2>$null if ($TenantId -and $tenantNow -and ($tenantNow -ne $TenantId)) { throw "az is signed in to tenant $tenantNow, not $TenantId. Run 'az login --tenant $TenantId --allow-no-subscriptions' first." } Write-Host "Preparing tenant $($tenantNow ?? $TenantId)" Write-Host "" $created = 0 foreach ($s in $services) { $existing = az ad sp list --filter "appId eq '$($s.AppId)'" --query "[0].id" -o tsv 2>$null if ($existing) { Write-Host (" present {0,-22} {1} ({2})" -f $s.Name, $s.AppId, $s.Why) continue } if ($PSCmdlet.ShouldProcess("$($s.Name) ($($s.AppId))", "create service principal")) { az ad sp create --id $s.AppId --only-show-errors | Out-Null if ($LASTEXITCODE -ne 0) { throw "Could not create the entry for $($s.Name). You need the Cloud Application Administrator, Application Administrator or Global Administrator role in this tenant." } Write-Host (" created {0,-22} {1} ({2})" -f $s.Name, $s.AppId, $s.Why) -ForegroundColor Green $created++ } } Write-Host "" if ($created -gt 0) { Write-Host "Done. Allow a minute for the change to propagate, then grant admin consent to Icon Map:" -ForegroundColor Yellow } else { Write-Host "Nothing to do - the tenant is already prepared. Grant admin consent to Icon Map if you have not yet:" -ForegroundColor Yellow } Write-Host " https://www.icon-map.com/documentation/fabric/onboarding/admin-consent/"