Recently at work I was writing a script to pull all Azure Advisor recommendations for a set of subscriptions for further analysis and display, and I wanted to make sure that my output included as much information as possible. The list of recommendations is readily available via the API, and based on the example output I thought - perfect! This should have all of the information I could need!

  • Category? Check!
  • Impact? Check!
  • Problem description? Check!
  • Impacted resources? Check!
  • Potential benefits? Check!
  • Learn More Link? Check!

And so I gleefully got my Powershell script written, made the API calls and started to parse through the returned object:

{
  "properties": {
    "category": "HighAvailability",
    "impact": "High",
    "impactedField": "Microsoft.Subscriptions/subscriptions",
    "impactedValue": "05750073-33cc-4d8a-9fbd-2d8163056078",
    "lastUpdated": "2025-05-28T03:26:35.4196762Z",
    "recommendationTypeId": "242639fd-cd73-4be2-8f55-70478db8d1a5",
    "shortDescription": {
      "problem": "Create an Azure Service Health alert",
      "solution": "Create an Azure Service Health alert"
    },
    "extendedProperties": {
      "recommendationControl": "MonitoringAndAlerting",
      "recommendationSubCategory": "MonitoringAndAlerting",
      "maturityLevel": "GA",
      "recommendationOfferingId": "ed05f3b7-8949-4698-9b38-49ab8abb5ee0"
    },
    "resourceMetadata": {
      "resourceId": "/subscriptions/05750073-33cc-4d8a-9fbd-2d8163056078"
    }
  },
  "id": "/subscriptions/05750073-33cc-4d8a-9fbd-2d8163056078/providers/Microsoft.Advisor/recommendations/b6b23db1-f330-66df-281f-575772a59d48",
  "type": "Microsoft.Advisor/recommendations",
  "name": "b6b23db1-f330-66df-281f-575772a59d48"
}

Where…where are my Potential Benefits? My Learn More Link? All of the extended properties that add more value to this information!

Well, it’s not here. And that created a problem. Without that information, the utility of the output was vastly reduced. A quick Google revealed I wasn’t the only person who’d had this problem, with GitHub issues being reported as far back as 2022 (without resolution).

I added to one of these existing issues and some more details of my experience, to see if I could get some traction, and thankfully one of the Microsoft developers responded quite quickly with the solution! So in the interest of sharing - the Advisor Metadata API endpoint includes details of each recommendation that can be joined to the data from the above API to provide that additional context and utility.

The resulting Powershell script I include below (which includes the API looping from my previous post):

$accessToken = Get-AzAccessToken -ResourceUrl "https://management.azure.com" -AsSecureString | Select-Object -ExpandProperty Token | ConvertFrom-SecureString -AsPlainText

#Build the headers for the authenticated API calls
$headers = @{
    "authorization" = "bearer $accessToken"
    "content-type"  = "application/json"
}

#Build an object of extended properties for recommendations for future lookups
$extendedPropertiesURI = "https://management.azure.com/providers/Microsoft.Advisor/metadata?api-version=2025-01-01&`$expand=ibiza"
$extendedProperties = $($(Invoke-RestMethod -Method GET -Uri $extendedPropertiesURI -Headers $headers).value | Where-Object { $_.Name -eq "recommendationType" }).properties.supportedValues

$subObject = $(Get-AzContext).Subscription
$subName = $subObject.Name
$subId = $subObject.Id

$uri = "https://management.azure.com/subscriptions/$subId/providers/Microsoft.Advisor/recommendations?api-version=2025-01-01"

#iterates through all recommendations for a given subscription, utilising the nextlink property for paginated resultes
$recommendations = do {
    $results = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers

    $results.value | foreach-object {
        $_
    }

    $nextLinkExists = [bool]($($results.Psobject.Properties.name -match "NextLink"))

    if ($nextLinkExists) {
        $uri = $results.NextLink
    }

} while ($nextLinkExists) 


$recommendations | foreach-object {

    $id = $_.properties.recommendationTypeId

    $_.properties | Add-Member -MemberType NoteProperty -Name "extendedMetadata" -Value $( $extendedProperties | Where-Object { $_.Id -eq $id } )
}

NB - This solution is sourced from this response to my comment on the GitHub issue, and refactored for Powershell.