If you've been using Azure Pipelines for a while, you might have made use of the Variable group feature (under the Library tab). These provide a way of defining a group of variables that can be referenced both by 'Classic' Release pipelines and the newer YAML-based pipelines.

variable group in the Azure DevOps Pipelines UI

You might get to a point where you realise that a lot of the variables being defined in variable groups would be better off being declared directly in a YAML file. That way you get the benefit of version control history. Obviously, you wouldn't commit any secrets in your source code, but other non-sensitive values should be fine. Secrets are better left in a variable group, or better yet as an Azure Key Vault secret.

I came up with the following PowerShell script that makes use of the Azure CLI commands to convert a variable group into the equivalent YAML syntax.

param (
    [Parameter(Mandatory=$true)]
    [string]
    $GroupName,
    [string]
    $Organisation,
    [string]
    $Project,
    [switch]
    $Array
)

$ErrorActionPreference = 'Stop'

# Find id of group
$groups = (az pipelines variable-group list --organization "https://dev.azure.com/$Organisation" --project "$Project") | ConvertFrom-Json

$groupId = $groups | Where-Object { $_.name -eq $GroupName } | Select-Object -ExpandProperty id -First 1

$group = (az pipelines variable-group show --id $groupId --organization "https://dev.azure.com/$Organisation" --project "$Project") | ConvertFrom-Json

$group.variables | Get-Member -MemberType NoteProperty | ForEach-Object {

    if ($Array.IsPresent) {
        Write-Output "- name: $($_.Name)"
        Write-Output "  value: $($group.variables.$($_.Name).Value)"
    } else {
        Write-Output "  $($_.Name): $($group.variables.$($_.Name).Value)"
    }
}

The script is also in this GitHub Gist.

If I run the script like this:

.\Convert-VariableGroup.ps1 -Organisation gardiner -GroupName "My Variable Group" -Project "GitHub Builds"

Then it produces:

And_More: $(Another.Thing)
Another.Thing: Another value
ASecret:
Something: A value

If I add the -Array switch, then the output changes to:

- name: And_More
  value: $(Another.Thing)
- name: Another.Thing
  value: Another value
- name: ASecret
  value:
- name: Something
  value: A value

Note that the variable which was marked as 'secret' doesn't have a value.