Azure Advisor - Update a recommendation suppression with Bicep


Intro

This article is part of a series: Navigate to series page

In this post I show how to update an existing Azure Advisor recommendation suppression - most commonly to extend (or shorten) its TTL - by redeploying the same Bicep template from Part 3.

There is no separate “update” operation

The Advisor suppressions REST API only exposes PUT (create), GET (list/read), and DELETE. There is no dedicated update verb. The way you “update” a suppression is by sending another PUT request to the same resourceUri/recommendationId/name combination with different property values - Advisor overwrites the existing suppression in place.

This maps cleanly onto Bicep/ARM’s normal deployment behavior: as long as the resource name (and its parent scope) stays the same, redeploying the template is treated as an update to the existing resource rather than a new create.

Update by redeploying with a new parameter value

Take the same template from Part 3:

targetScope = 'subscription'

@description('The Advisor recommendation resource name (identifier, not always a GUID) to suppress.')
param recommendationId string

@description('A friendly, deterministic name for this suppression - must match the existing suppression to update it.')
param suppressionName string = 'reserved-instance-cost-suppression'

@description('Duration the suppression is valid for, in TimeSpan format d.hh:mm:ss.')
param ttl string = '90.00:00:00'

resource recommendation 'Microsoft.Advisor/recommendations@2023-01-01' existing = {
  name: recommendationId
}

resource suppression 'Microsoft.Advisor/recommendations/suppressions@2023-01-01' = {
  parent: recommendation
  name: suppressionName
  properties: {
    suppressionId: guid(subscription().id, recommendationId, suppressionName)
    ttl: ttl
  }
}

To extend the suppression from 90 days to 180 days, redeploy with a new ttl value and the same suppressionName:

New-AzSubscriptionDeployment `
    -Location "westeurope" `
    -TemplateFile "./suppress-reserved-instance.bicep" `
    -recommendationId $recommendationId `
    -suppressionName "reserved-instance-cost-suppression" `
    -ttl "180.00:00:00"
az deployment sub create \
  --location westeurope \
  --template-file ./suppress-reserved-instance.bicep \
  --parameters recommendationId=$recommendationId suppressionName=reserved-instance-cost-suppression ttl="180.00:00:00"

Because suppressionId is derived deterministically with guid(subscription().id, recommendationId, suppressionName), it stays identical between the create and the update deployment - only ttl changes. This matters: if suppressionId changed on every deployment (for example if it were randomly generated), Advisor would still update the same suppression resource (name-based), but you’d lose the ability to correlate the suppression’s identity across deployments in your own records.

Verify the update

Query the suppression again and confirm expirationTimestamp moved out:

$verifyUri = "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Advisor/recommendations/$recommendationId/suppressions/reserved-instance-cost-suppression?api-version=$apiVersion"
Invoke-RestMethod -Uri $verifyUri -Method Get -Headers $headers | ConvertTo-Json -Depth 10

Adapting this into a pipeline

A useful pattern is a scheduled pipeline that re-evaluates whether a suppression is still justified before extending it:

  1. On a schedule (for example monthly), read your suppressions.json (or similar source-controlled list) that records each suppression’s business justification and a “review by” date.
  2. If the justification is still valid, redeploy the Bicep template with an extended ttl and require a pull request approval for the change - this keeps the extension auditable instead of silently renewing forever.
  3. If the justification has expired or is no longer valid, remove the suppression entry from your source file and let Part 5 - Delete a suppression clean it up.

This avoids the common failure mode with snoozed recommendations: a suppression is created once “temporarily” and then never revisited because nothing forces a re-review.

In the next post I cover removing a suppression entirely, including why this needs a slightly different approach than a normal Bicep resource deletion:

Azure Advisor - Delete a suppression