Deploy ARM template to a specific region

Page content

Introduction

The Azure Resource Manager uses management endpoints to receive requests. This service is resilient and deployed to all regions and offers control plane operations, which are sent to management.azure.com. Talking to any endpoint is fine and you do not need to use a region-specific URL if you deploy to Azure with ARM, Bicep or Terraform.

In case you want to send a request to a region, this post shows you how you can do this.

Regional Deployment

You need an ARM template to deploy and optionally a parameter file. This template is then sent to the region specific management endpoint https://$location.management.azure.com. That’s about it. The rest of the work/script is used to build the headers and parameters for the webrequest.

The script will be called with the parameters: .\deploy.ps1 -SubscriptionId "<yoursubscriptionid>" -Location germanywestcentral -TemplateFilePath "C:\someplace\main.json" -ParameterFilePath "C:\someplace\parameters-.json"

Convert Bicep to ARM

You are using Bicep? No problem. Quickly convert it to ARM with bicep build .\yourtemplate.bicep and you have the ARM template json version to continue.

PowerShell Script

To find out which API version can be used, look at Azure resource providers and types and replace the samples accordingly. In our case it would be az provider show --namespace Microsoft.Resources --query "resourceTypes[?resourceType=='deployments'].apiVersions | [0]" --out table

<#
========================================================================================================================================
AUTHOR:  René Hézser
DATE:    28/12/2023
Version: 1.0
Comment: 
- The script deploys an ARM template to the management endpoint in a specific region
- The script uses the currently logged in user to authenticate against Azure
========================================================================================================================================
#>
[CmdLetBinding()]
param(
  [Parameter(Mandatory = $true)]
  [ValidateScript({
      try {
        [System.Guid]::Parse($_) | Out-Null
        $true
      }
      catch {
        $false
      }
    })]
  [string]$SubscriptionId,
  [parameter(Mandatory = $false)][ValidateNotNullOrEmpty()][string]$location = 'westeurope',
  [Parameter(Mandatory = $true)][validatescript({ test-path $_ -PathType Leaf })][string]$TemplateFilePath,
  [Parameter(Mandatory = $false)][validatescript({ test-path $_ -PathType Leaf })][string]$ParameterFilePath
)

# create deployment variables
$UTCNow = (get-date).ToUniversalTime().tostring('yyyyMMddHHmmss')
$DeploymentName = "SubLevelDeployment-$UTCNow"
$URI = "https://$location.management.azure.com/subscriptions/$SubscriptionId/providers/Microsoft.Resources/deployments/$DeploymentName`?api-version=2019-10-01"
$Token = (Get-AzAccessToken).Token
$RequestHeaders = @{'Authorization' = 'Bearer ' + $Token }
Write-Host "Creating deployment '$DeploymentName' in $location" -ForegroundColor Cyan

# get the template content (and parameters if provided)
$TemplateContent = Get-Content -Path $TemplateFilePath -Raw
If ($PSBoundParameters.ContainsKey('ParameterFilePath')) {
   $ParametersFileJSONContent = ConvertFrom-JSON $(Get-Content -Path $ParameterFilePath -Raw)
   $ParametersContent = ConvertTo-JSON $ParametersFileJSONContent.parameters
   $RequestBody = @"
{
    "properties": {
        "template": $TemplateContent,
        "parameters": $ParametersContent,
        "mode": "Incremental"
    },
    "location": "$location"
}
"@
Write-Host "RequestBody: $RequestBody" -ForegroundColor Yellow
  }
  else {
    $RequestBody = @"
{
    "properties": {
        "template": $TemplateContent,
        "mode": "Incremental"
    },
    "location": "$location"
}
"@
Write-Host "RequestBody: $RequestBody" -ForegroundColor Yellow
}

# deploy the template
Try {
   $DeployTemplateRequest = Invoke-WebRequest -UseBasicParsing -Uri $URI -Method PUT -Headers $RequestHeaders -Body $RequestBody -ContentType 'application/json'
   If ($DeployTemplateRequest.statuscode -ge 200 -and $DeployTemplateRequest.statuscode -le 299) {
      Write-Host "Template deployment request successfully submitted." -ForegroundColor Yellow
   }
   else {
      Write-Error "The deployment '$DeploymentName' has failed. Error Code: $($DeployTemplateRequest.properties.error.code), Error Message: $($DeployTemplateRequest.properties.error.message)"
      Foreach ($Detail in $DeployTemplateRequest.properties.error.details) {
         Write-Error "$Detail.message"
      }
   }
}
Catch {
   $ExceptionDetails = $_.Exception.Response.GetResponseStream()
   $reader = New-Object System.IO.StreamReader($ExceptionDetails)
   $ExceptionResponse = $reader.ReadToEnd();
   Write-Error $ExceptionResponse
   Write-Error $_.ErrorDetails
   throw $_.Exception
}

Summary

You can communicate to an Azure Resource Manager endpoint in a specific region by sending the deployment request to location.management.azure.com.