Streamlining Azure Quota Management using PowerShell

Managing Azure resources efficiently requires a keen eye on various factors, one of the more critical being quota limits. Azure quotas dictate the maximum number of resources you can provision within your subscription. While these limits are set to ensure resource availability and performance, they can sometimes hinder your operations if not managed effectively.

In this blog post, I’ll cover how you can streamline the process of monitoring them. Traditional methods of reviewing quota limits through the Azure portal can be time-consuming, especially when dealing with multiple subscriptions. Each category must be loaded individually, leading to tedious navigation and potential oversight.

Fortunately, there’s a solution. I’ve created a PowerShell script designed to simplify and expedite the process of generating a comprehensive report on Azure quota limits. The script allows users to effortlessly gather data on quota limits, current usage, and identify any limits that are approaching or exceeding a predefined threshold.

The Script

The PowerShell script provided below is designed to streamline the process of generating a detailed report on Azure quota limits. Before running the script, please ensure you have updated the variables shown below –

  1. $quotaWarningLevel: This variable determines the percentage level at which warnings are triggered for quota limits. Users can adjust this value according to their preference and requirements.
  2. $quotaActualWarningAmount: This variable determines an actual count below the limit to generate a warning on, this will only trigger of quota’s with a limit greater than 1.
  3. $subscriptionsToScan: Users can specify a list of subscription names to scan. Leaving this field empty will result in scanning all available subscriptions.
  4. $tenantId: This variable requires the Tenant ID to scan. Users must update it with their own Tenant ID.

Once the parameters are configured, the script authenticates to Azure as the current user, retrieves subscription information, and gathers usage data for various resources across all available locations. It then creates a detailed report in CSV format, highlighting each resource’s name, current usage, limit, subscription, and location.

Finally, the script concludes by displaying a completion message and opening the generated report for further analysis.

$quotaWarningLevel = 90 # percentage level to warn at
$quotaActualWarningAmount = 4 # The amount of remaining usage before warning
$subscriptionsToScan = @("Sandbox")
$tenantId = "####" 

$date = Get-Date
$reportExportPath = "c:\temp\QuotaReport-$($date.Year)$($date.Month)$($date.Day)$($date.Millisecond).csv"


Connect-AzAccount -TenantId $tenantId
$subscriptions = Get-AzSubscription

# Get available locations to query API
$apiRegisteredUsageProvider = Get-AzResourceProvider -ProviderNamespace Microsoft.Compute -ApiVersion "2024-03-01" | Where-Object {$_.ResourceTypes.ResourceTypeName -eq 'locations/usages'}
$availableLocations = $apiRegisteredUsageProvider.Locations

$currentIndex = 1
foreach( $subscription in $subscriptions) {
    # Skip Subscriptions if there's a $subscriptionsToScan list define where it doesn't match
    if($null -ne $subscriptionsToScan -and !($subscriptionsToScan.Contains($subscription.Name))) {
        Write-Host "Skipped $($subscription.Name) due to filter"
        continue
    }

    Get-AzSubscription -SubscriptionName $subscription.Name -WarningAction SilentlyContinue | Set-AZContext -WarningAction SilentlyContinue

    Write-Host "Starting on $($subscription.name)"

    $locIndex = 1
    foreach($loc in $availableLocations) {
        # Show a nice progress bar
        Write-Progress -Id 0 -Activity "Processing '$($subscription.name)', Location $($loc)" -Status "$locIndex of $($availableLocations.Count)" -PercentComplete (($locIndex / $availableLocations.Count) * 100)
        
        $allUsageData = Get-AzNetworkUsage -Location $loc # Network resources
        $allUsageData += Get-AzVMUsage -Location $loc # Virtual machine resources
        $allUsageData += Get-AzStorageUsage -Location $loc # Storage Accounts

        $exportObject = @()
        foreach($usageData in $allUsageData) {
            $warn = $false
            if($usageData.CurrentValue -gt $usageData.Limit * ($quotaPercentageWarningLevel / 100)) {
                $warn = $true
            } elseif ($usageData.Limit -gt 1 -and $usageData.CurrentValue -gt $usageData.Limit - $quotaActualWarningAmount) {
                $warn = $true
            }

            $exportObject += [PSCustomObject]@{
                Name = $null -eq $usageData.Name.LocalizedValue ? $usageData.Name : $usageData.Name.LocalizedValue
                Warning = $warn
                CurrentValue = $usageData.CurrentValue
                Limit = $usageData.Limit
                Subscription = $subscription.Name
                Location = $loc
            }
        }

        # Create and/or append to existing file
        if($currentIndex -eq 1) {
            $exportObject | Export-Csv -Path $reportExportPath
        } else {
            $exportObject | Export-Csv -Path $reportExportPath -Append
        }

        $locIndex++
        $currentIndex++
    }
    Write-Progress -Id 0 -Activity " " -Status " " -Completed
}

Write-Host -ForegroundColor Green "Completed Script"
Invoke-Item $reportExportPath

EDIT: I’ve updated the script on the 4th of June 2026 to include an additional $quotaActualWarningAmount variable which will also alert if you’re within a given number of your limit. This will only trigger on quota’s with a limit greater than 1.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.