Variable groups in VSTS are a very useful feature that allows you to share common variables and secrets across builds and releases.

While being able to link a variable in several places can be a real time saver, changing those variables – for many – is still a manual task.

This can cause quite a bit of overhead if you are regularly rolling over your passwords and keys for example.

It is also a significant risk for human failure.
In this article, I’d like to show you how you can automate the update process and minimise the potential risk.

In this example I have a variable group with a single variable set up:

As you can see the variable is called MySecret, but at the moment we have put a plain text placeholder “nothing here yet” in the field.

We can link “MyAutoGroup” to all releases and builds that need to use “MySecret”.

We have two ways of automating the update of MySecret:

  • Use KeyVault integration
    • allows us to use hardware backing
    • if we update the secret in KeyVault, it updates automatically in the variable group
    • this comes at the extra cost of having a KeyVault
  • Use the REST API
    • allows us to set the secret on the command line
    • less secure than the KeyVault method (we still get 2048-bit software encryption on the VSTS side though)
    • this does not come with an extra cost (included in VSTS licencing)

In this article I will focus on the REST API method only.

First, we need to use a personal access token to log into VSTS on the command line.

I am using PowerShell here, but any REST client will do.

Once we have our credentials, we need to look up the group that we want to change, as we need the exact id.

Then we use the appropriate REST call to change the variable group.

$personalAccessToken = "YOUR_PAT_TOKEN_GOES_HERE"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "",$personalAccessToken)))
$accountname = "YOUR_ACCOUNT_NAME_GOES_HERE"
$variableGroupName = "YOUR_VARIABLE_NAME_GOES_HERE"
$projectName = "YOUR_PROJECT_NAME_GOES_HERE"

$vstsUri = "https://" + $accountname + ".visualstudio.com/"

# GET https://{accountName}.visualstudio.com/{project}/_apis/distributedtask/variablegroups?api-version=4.1-preview.1
# get variable groups and find our one
$call = $vstsUri + $projectName + "/_apis/distributedtask/variablegroups?api-version=4.1-preview.1"
$result = Invoke-RestMethod -Uri $call -Method Get -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}

$groupId = (-1)
foreach($group in $result.value) {

if($group.name.Equals($variableGroupName)) {

$groupId = $group.id
break;

}

}
# if we can't find the group, throw an error
if($groupId -lt 0) {

throw("Couldn't find group")

}

# get full json for our group
$call = $vstsUri + $projectName + "/_apis/distributedtask/variablegroups/" + $groupId + "?api-version=4.1-preview.1"
$group = Invoke-RestMethod -Uri $call -Method Get -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}

# https://docs.microsoft.com/en-us/rest/api/vsts/_apis/distributedtask/variablegroups/variablegroups/update?view=vsts-rest-4.1
# update variable group by id

$group.variables.MySecret = @{}

$group.variables.MySecret += @{"value" = "New Secret Value"}
$group.variables.MySecret += @{"isSecret" = $true}

$call = $vstsUri + $projectName + "/_apis/distributedtask/variablegroups/" + $groupId + "?api-version=4.1-preview.1"
$result = Invoke-RestMethod -Uri $call -Method Put -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body (ConvertTo-Json $group -Depth 10)

This is what the end result looks like:

You can find this script on GitHub as well.