Passing dynamically sized object parameters to Azure DevOps Pipeline templates

The Problem

I have an Azure DevOps YAML template that does some deployment actions using PowerShell. This template is used multiple locations. The problem is that the PowerShell step within the template needs a variable number of environment variables, set from values stored in an Azure DevOps variable Group. The number of variables is not fixed because they depend on the underlying commands the PowerShell script is triggering to do the deployment.

Hence, the problem was how to pass the values of these variables to the template in a way that was easy to maintain and understand, as this is not something that is well documented.

The Solution

The solution, as you might expect if you have used YAML templates, is to use the object type for the parameter in the template. This allows you to pass a single object to the template that contains all the values you need.

This can be seen in this simple example

parameters:
  - name: envparams
    type: object
    default:

steps:
- task: PowerShell@2
  inputs:
    targetType: 'inline'
    script: |
      Get-ChildItem -Path Env:      
  env:  ${{ parameters.envparams }}

The question then becomes, how to you wire this up in the calling pipeline?

The answer is you pass a JSON block to the template. Just make sure you get the escaping correct, I have found this is the most common reason for a pipeline to fail to run.

trigger:
- main

pool:
  vmImage: ubuntu-latest

variables:
  # Link to the variable group
  - group: ExpandTest
steps:
- template: base.yml
  parameters:
    # match the variable group values with name of the environment variables you wish to create
    envparams: {
      'MY-PARAM1': '$(MY-PARAM1)',
      'MY-PARAM2': '$(MY-PARAM2)'
    }