Script to Assign Permission at Subscription Level
  • 17 Jun 2026
  • 4 Minutes to read
  • Dark
    Light
  • Download PDF

Script to Assign Permission at Subscription Level

  • Dark
    Light
  • Download PDF

Article summary

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

  1. Make sure you have elevated permissions  for Global Admin / Tenant Owner

  2. Ensure you have the Service Principal (App Registration Already Setup) and have its client id

  3. Ensure you have the list of subscription id’s you want to give access to

  4. 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]

  1. 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]
  1. 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


Was this article helpful?