Parse ARM Template JSON Outputs In Azure Pipelines
It is common to have an ARM template deployment step as part of a pipeline/release in Azure DevOps. During this step resources are created or modified and we often want to export their names, URIs, IP addresses, keys for further use in the pipeline.
In this short article, we will take a look at how to parse outputs from an ARM template using PowerShell and Bash for both YAML-based and Classic release pipelines.
Contents:
- Defining Sample Outputs Section
- How To Set Pipeline Variable In Scripts
- Should I Use Bash Or PowerShell?
- YAML Pipeline
- Classic Release
Defining Sample Outputs Section
To make our discussion easier to follow, let’s define a very simple ARM template that returns someResourceUri as part of outputs section.
Our goal is to retrieve someResourceUri value in the pipeline and create corresponding pipeline variable so that we can use it in the next steps.
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "resources": [],
    "outputs": {
        "someResourceUri": {
            "type": "string",
            "value": "https://example.com"
        }
    }
}
How To Set Pipeline Variable In Scripts
In order to use output values from ARM template deployment somewhere further in a pipeline, we need to be able to create pipeline variables from parsed values.
It can be achieved using task.setvariable logging command. Logging command is a way for tasks and scripts to communicate with the agent, read more about syntax here.
There is a section in docs about setting variables in scripts, but to keep it short, refer to the example below where myVar is the name of a pipeline variable, and someValue is value =).
echo "##vso[task.setvariable variable=myVar]someValue"
We will use this functionality to set variables for both YAML pipelines and Classic releases.
Should I Use Bash Or PowerShell?
This decision is completely up to you, in this post we will look how to do it with either of them. But here are just a few notes:
- In examples we use pwsh - PowerShell Core which is the cross-platform version
- Microsoft-hosted agents usually have both pwsh and bash installed on both windows and linux agents, more information here
- If your agents are self-hosted, then choice is simple, just use what’s available
YAML Pipeline
Below is shown a sample ARM template deployment step, and its outputs we would like to parse.
NOTE: Outputs are assigned to a pipeline variable armOutputs (deploymentOutputs setting).
- stage: DEV
  jobs:
  - job: Deploy
    steps:
    - task: AzureResourceManagerTemplateDeployment@3
      inputs:
        deploymentScope: 'Resource Group'
        azureResourceManagerConnection: '...'
        subscriptionId: '8a918a0a-b436-484b-8317-fa5bb7fb9f67'
        action: 'Create Or Update Resource Group'
        resourceGroupName: 'rg-contoso'
        location: 'West US'
        templateLocation: 'Linked artifact'
        csmFile: 'template.json'
        deploymentMode: 'Incremental'
        deploymentOutputs: 'armOutputs'
PowerShell
So, this is the actual part where we parse output values. Note that the second step just logs the parsed value, so you won’t probably need it.
- ConvertFrom-Json is used to parse JSON
- armOutputsobject is passed as- ARM_OUTPUTSenvironment variable
- Using pwsh task
- pwsh: |
    $outputsObject = $env:ARM_OUTPUTS | ConvertFrom-Json
    Write-Host "##vso[task.setvariable variable=someResourceUriPwsh]$($outputsObject.someResourceUri.value)"
  displayName: 'Parse ARM deploymentOutputs | pwsh'
  env:
    ARM_OUTPUTS: $(armOutputs)
- script: echo $(someResourceUriPwsh)
  displayName: 'Log someResourceUriPwsh'
Bash
Here is another way to parse outputs:
- jq is used for parsing JSON, ‘-r’ flag is passed to get value without quotes
- armOutputsobject is passed as- ARM_OUTPUTSenvironment variable
- Using bash task
- bash: |
    echo "##vso[task.setvariable variable=someResourceUriBash]$(echo $ARM_OUTPUTS | jq -r '.someResourceUri.value')"
  displayName: 'Parse ARM deploymentOutputs | bash'
  env:
    ARM_OUTPUTS: $(armOutputs)
- script: echo $(someResourceUriBash)
  displayName: 'Log someResourceUriBash'
Classic Release
The idea here is literally the same, the only difference is that it is now done through UI. We can use the same approach to set pipeline variables in scripts as illustrated above.
I will only briefly describe the steps since it’s quite similar to what we’ve already discussed before.
PowerShell
- Add PowerShell task
- Use inline script
- Check “Use PowerShell Core” option in “Advanced” section
- Set ARM_OUTPUTSvariable to$(armOutputs)in “Environment Variables” section
$outputsObject = $env:ARM_OUTPUTS | ConvertFrom-Json
Write-Host "##vso[task.setvariable variable=someResourceUriPwsh]$($outputsObject.someResourceUri.value)"
Bash
- Add Bash task
- Use inline script
- Set ARM_OUTPUTSvariable to$(armOutputs)in “Environment Variables” section
echo "##vso[task.setvariable variable=someResourceUriBash]$(echo $ARM_OUTPUTS | jq -r '.someResourceUri.value')"