- 17 Jun 2026
- 4 Minutes to read
- Print
- DarkLight
- Download PDF
Script to Assign Permission at Subscription Level
- Updated on 17 Jun 2026
- 4 Minutes to read
- Print
- DarkLight
- Download PDF
This script will help you to setup access for the Turbo360 App Registration you want to use with Cost Analyzer where you want to apply access at subscription level.
Before Running the Script
Make sure you have elevated permissions for Global Admin / Tenant Owner
Ensure you have the Service Principal (App Registration Already Setup) and have its client id
Ensure you have the list of subscription id’s you want to give access to
Log into the Azure CLI to get an Azure Resource Manager scoped token with the below command
az login --use-device-code --tenant [Tenant ID]
Log into Azure CLI and get a Microsoft Graph API scoped token with the below command
az login --use-device-code --scope https://graph.microsoft.com//.default --tenant [Tenant ID]Modify and run the below script to setup
Script
The below script can be used and you can update the client id and subscription ID’s in the script as required or add more than 1 client ID/Subscription combination.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# --------------------------------------------
$RoleName = "Reader"
# Each entry: ClientId (App ID) + the subscriptions it should be granted access to
$Assignments = @(
@{
ClientId = "[Client-ID-1]"
SubscriptionIds = @(
"[Sub-ID-1]",
"[Sub-ID-2]",
"[Sub-ID-3]",
"[Sub-ID-4]",
"[Sub-ID-5]"
)
}
)
# ---------------------------------------------------------------------------
# Functions
# ---------------------------------------------------------------------------
function Assert-AzCliLoggedIn {
$account = az account show 2>$null | ConvertFrom-Json
if (-not $account) {
throw "Not logged in to Azure CLI. Please run 'az login' before executing this script."
}
Write-Host "Logged in as: $($account.user.name)" -ForegroundColor Green
}
function Get-ServicePrincipalObjectId {
param([string]$ClientId)
$result = az ad sp show --id $ClientId --query id --output tsv 2>$null
if (-not $result) {
throw "Service Principal not found for ClientId: $ClientId"
}
return $result.Trim()
}
function Set-RoleAssignment {
param(
[string]$ObjectId,
[string]$ClientId,
[string]$SubscriptionId,
[string]$RoleName
)
$scope = "/subscriptions/$SubscriptionId"
# Check if the assignment already exists
$existing = az role assignment list `
--assignee $ObjectId `
--role $RoleName `
--scope $scope `
--query "[0].id" `
--output tsv 2>$null
if ($existing) {
return [PSCustomObject]@{
ClientId = $ClientId
SubscriptionId = $SubscriptionId
Status = "SKIPPED (already exists)"
}
}
az role assignment create `
--assignee-object-id $ObjectId `
--assignee-principal-type ServicePrincipal `
--role $RoleName `
--scope $scope `
--output none 2>$null
if ($LASTEXITCODE -ne 0) {
return [PSCustomObject]@{
ClientId = $ClientId
SubscriptionId = $SubscriptionId
Status = "FAILED"
}
}
return [PSCustomObject]@{
ClientId = $ClientId
SubscriptionId = $SubscriptionId
Status = "ASSIGNED"
}
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
Assert-AzCliLoggedIn
$results = [System.Collections.Generic.List[PSCustomObject]]::new()
foreach ($entry in $Assignments) {
$clientId = $entry.ClientId
Write-Host "`n--- Service Principal: $clientId ---" -ForegroundColor Cyan
try {
$objectId = Get-ServicePrincipalObjectId -ClientId $clientId
} catch {
Write-Warning $_.Exception.Message
foreach ($subId in $entry.SubscriptionIds) {
$results.Add([PSCustomObject]@{
ClientId = $clientId
SubscriptionId = $subId
Status = "FAILED (SP not found)"
})
}
continue
}
foreach ($subscriptionId in $entry.SubscriptionIds) {
Write-Host " Assigning '$RoleName' on $subscriptionId ..." -NoNewline
$result = Set-RoleAssignment `
-ObjectId $objectId `
-ClientId $clientId `
-SubscriptionId $subscriptionId `
-RoleName $RoleName
$color = switch ($result.Status) {
{ $_ -like "ASSIGNED*" } { "Green" }
{ $_ -like "SKIPPED*" } { "Yellow" }
default { "Red" }
}
Write-Host " $($result.Status)" -ForegroundColor $color
$results.Add($result)
}
}
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
Write-Host "`n========== SUMMARY ==========" -ForegroundColor Cyan
$results | Format-Table -AutoSize
$assigned = @($results | Where-Object Status -eq "ASSIGNED").Count
$skipped = @($results | Where-Object { $_.Status -like "SKIPPED*" }).Count
$failed = @($results | Where-Object { $_.Status -like "FAILED*" }).Count
Write-Host "Assigned : $assigned" -ForegroundColor Green
Write-Host "Skipped : $skipped" -ForegroundColor Yellow
Write-Host "Failed : $failed" -ForegroundColor Red