Back to Blog
4 min read

Azure Advisor Score: Measuring Your Cloud Excellence

Azure Advisor Score provides a single metric to measure how well your Azure environment follows best practices. Let’s explore how to improve your score and operationalize Advisor recommendations.

Understanding Advisor Score

Advisor Score is calculated across five categories:

  • Cost (reduce spending)
  • Security (protect workloads)
  • Reliability (ensure availability)
  • Operational Excellence (improve operations)
  • Performance (optimize speed)

Getting Your Advisor Score

# Get overall Advisor score
$score = Invoke-AzRestMethod -Method GET `
    -Path "/subscriptions/$((Get-AzContext).Subscription.Id)/providers/Microsoft.Advisor/advisorScore?api-version=2020-09-01"

$scoreData = ($score.Content | ConvertFrom-Json).value

foreach ($category in $scoreData) {
    Write-Host "$($category.name): $([math]::Round($category.properties.score * 100, 1))%"
}

Retrieving Recommendations

using Azure.ResourceManager;
using Azure.ResourceManager.Advisor;
using Azure.Identity;

public class AdvisorService
{
    private readonly ArmClient _armClient;

    public AdvisorService()
    {
        _armClient = new ArmClient(new DefaultAzureCredential());
    }

    public async Task<List<RecommendationSummary>> GetRecommendationsAsync(string subscriptionId)
    {
        var subscription = _armClient.GetSubscriptionResource(
            new ResourceIdentifier($"/subscriptions/{subscriptionId}"));

        var recommendations = new List<RecommendationSummary>();

        await foreach (var rec in subscription.GetAdvisorRecommendations().GetAllAsync())
        {
            recommendations.Add(new RecommendationSummary
            {
                Category = rec.Data.Category.ToString(),
                Impact = rec.Data.Impact.ToString(),
                Problem = rec.Data.ShortDescription?.Problem,
                Solution = rec.Data.ShortDescription?.Solution,
                ResourceId = rec.Data.ResourceMetadata?.ResourceId,
                PotentialBenefits = rec.Data.ExtendedProperties?.GetValueOrDefault("annualSavingsAmount")
            });
        }

        return recommendations.OrderByDescending(r => r.Impact).ToList();
    }
}

public class RecommendationSummary
{
    public string Category { get; set; }
    public string Impact { get; set; }
    public string Problem { get; set; }
    public string Solution { get; set; }
    public string ResourceId { get; set; }
    public string PotentialBenefits { get; set; }
}

Automating Recommendation Implementation

# Auto-implement safe recommendations
param(
    [string]$SubscriptionId,
    [string[]]$Categories = @('Cost'),
    [switch]$WhatIf
)

$recommendations = Get-AzAdvisorRecommendation |
    Where-Object { $_.Category -in $Categories -and $_.Impact -eq 'High' }

foreach ($rec in $recommendations) {
    Write-Host "Processing: $($rec.ShortDescription.Problem)"

    # Handle specific recommendation types
    switch -Regex ($rec.RecommendationTypeId) {
        'e10b1381-5f0a-47ff-8c7b-37bd13d7c974' {
            # Right-size or shutdown underutilized VMs
            $vmId = $rec.ResourceMetadata.ResourceId
            $vm = Get-AzVM -ResourceId $vmId

            if ($rec.ExtendedProperties.recommendedSku) {
                $newSize = $rec.ExtendedProperties.recommendedSku
                Write-Host "  Recommended resize: $($vm.HardwareProfile.VmSize) -> $newSize"

                if (-not $WhatIf) {
                    $vm.HardwareProfile.VmSize = $newSize
                    Update-AzVM -VM $vm -ResourceGroupName $vm.ResourceGroupName
                }
            }
        }

        '57f30416-aa4d-45dc-b85a-b55c31fbd67e' {
            # Delete unattached disks
            $diskId = $rec.ResourceMetadata.ResourceId
            Write-Host "  Deleting unattached disk: $diskId"

            if (-not $WhatIf) {
                Remove-AzDisk -ResourceId $diskId -Force
            }
        }

        default {
            Write-Host "  Manual review required for: $($rec.RecommendationTypeId)"
        }
    }
}

Creating a Score Dashboard

// Log Analytics query for Advisor trends
AdvisorResources
| where type == "microsoft.advisor/recommendations"
| extend category = tostring(properties.category),
         impact = tostring(properties.impact),
         resourceId = tostring(properties.resourceMetadata.resourceId)
| summarize
    TotalRecommendations = count(),
    HighImpact = countif(impact == "High"),
    MediumImpact = countif(impact == "Medium"),
    LowImpact = countif(impact == "Low")
    by category
| order by HighImpact desc

CI/CD Integration

# .github/workflows/advisor-gate.yml
name: Advisor Score Gate

on:
  pull_request:
    branches: [main]
    paths:
      - 'infrastructure/**'

jobs:
  check-advisor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Azure Login
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Get Advisor Score
        id: advisor
        run: |
          # Get current score
          score=$(az rest --method get \
            --url "https://management.azure.com/subscriptions/${{ secrets.SUBSCRIPTION_ID }}/providers/Microsoft.Advisor/advisorScore?api-version=2020-09-01" \
            --query "value[?name=='Cost'].properties.score" -o tsv)

          echo "score=$score" >> $GITHUB_OUTPUT

          # Check for high-impact recommendations
          high_impact=$(az advisor recommendation list \
            --filter "Impact eq 'High'" \
            --query "length(@)")

          echo "high_impact=$high_impact" >> $GITHUB_OUTPUT

      - name: Check Score Threshold
        run: |
          score=${{ steps.advisor.outputs.score }}
          threshold=0.7

          if (( $(echo "$score < $threshold" | bc -l) )); then
            echo "::error::Advisor score ($score) is below threshold ($threshold)"
            exit 1
          fi

      - name: Comment on PR
        uses: actions/github-script@v6
        with:
          script: |
            const score = (${{ steps.advisor.outputs.score }} * 100).toFixed(1);
            const highImpact = ${{ steps.advisor.outputs.high_impact }};

            const body = `## Azure Advisor Score Report
            | Metric | Value |
            |--------|-------|
            | Current Score | ${score}% |
            | High Impact Recommendations | ${highImpact} |

            ${highImpact > 0 ? '**Action Required**: Address high-impact recommendations before deployment.' : 'No high-impact recommendations.'}`;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: body
            });

Scheduling Regular Reviews

// automation/advisor-review-automation.bicep
param location string = 'australiaeast'

resource automationAccount 'Microsoft.Automation/automationAccounts@2021-06-22' = {
  name: 'aa-advisor-automation'
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    sku: {
      name: 'Basic'
    }
  }
}

resource schedule 'Microsoft.Automation/automationAccounts/schedules@2021-06-22' = {
  parent: automationAccount
  name: 'weekly-advisor-review'
  properties: {
    frequency: 'Week'
    interval: 1
    startTime: '2022-01-01T09:00:00+00:00'
    timeZone: 'Australia/Sydney'
  }
}

Azure Advisor Score provides actionable insights to continuously improve your Azure environment’s health and efficiency.

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.