Passing variables from stage to stage in Azure DevOps release

If you have ever wanted to pass variables between the stages of your release this post will show you how. Using VSTeam you can update or add variables to your release with just a few lines of PowerShell. With PowerShell now being cross platform, this means you can do this from our hosted macOS, Linux or Windows agents.

It is important to point out you are changing the variables for a release and not the release definition itself. Any variables added are only added to the release and will not appear on the release definition. Also, any changes to values will only affect the release.

The key to all of this is REST API provided by Azure DevOps. The REST API provides calls to update a release which gives us access to the variables of that release. The icing on the cake is VSTeam. VSTeam is a PowerShell module that has already wrapped the required API calls to get and update a release.

To demonstrate I will create a release definition with two stages.


In Stage 1 I will install VSTeam and use it to get the current release, update one variable and add another and then update the release. I will do all of this from a single Inline PowerShell task.


The code for the task is below.

   1:  Install-Module VSTeam -Scope CurrentUser -Force
   2:  Set-VSTeamAccount –Account $(Acct) -PersonalAccessToken $(PAT)
   3:  $r = Get-VSTeamRelease -ProjectName "$(System.TeamProject)" `
             -Id $(Release.ReleaseId) -Raw
   4:  $r.variables.test.value = 'Set In Stage 1'
   5:  $r.variables | Add-Member NoteProperty `
             temp([PSCustomObject]@{value='Created in Stage 1'})
   6:  Update-VSTeamRelease -ProjectName "$(System.TeamProject)" `
             -Id $(Release.ReleaseId) -Release $r -Force

Let’s break down the code above.

On line 1 we are installing the VSTeam module on the agent. Be sure and set the Scope parameter to CurrentUser or you will get an error trying to install the module globally. You also need to add the Force switch to prevent any confirmations.

On line 2 we are connecting to the desired account using a personal access token. This is very important. Although VSTeam supports using the Access Token from AzD with Bearer authentication the token does not have enough permission to update a release. Therefore, you must create a personal access token that has the correct permissions. Store the personal access token as a secured variable in your release definition. Also create a variable named “Acct” that holds the name of the AzD organization you are running this release from. Lastly, add a variable named “Test” that we will update in the release.



UPDATE (7/19/2019):

After Stefan Stranger blogged he could not get my steps to work I tested the pipeline I used to create this post and it still worked. However, when I tried to follow this blog on a different pipeline in a different organization I was getting strange errors. The problem was the permissions. After reading Stefan’s post I started looking for permission issues and found them. If you make sure your ‘Team Module Build Service has the following permissions you can use the bearer token option of VSTeam and no longer need a PAT.



On line 3 we are getting the release we are running by using the predefined variables provided by AzD. The first variable we need is System.TeamProject. This gives us the name of the project we are running inside. The second variable is Release.ReleaseId which returns the id of the release. Finally, we must provide the Raw switch. This switch instructs the function to not modify the output in anyway. That way it can be returned to AzD in the update call. Without the Raw switch you will be returned a VSTeam.Release object. This object even when converted to JSON will not be the required shape to send back to AzD.

On line 4 we simply update an existing variable to a new value.

On line 5 we are adding a new variable named ‘temp’ to the release and setting its value to ‘Created in Stage 1’.

Finally, on line 6 we send the object back to AzD using the Update-VSTeamRelease function passing in the modified release.

Now, in the second stage of the release I will use PowerShell to simply output the values.

   1:  Write-Host $(Test)
   2:  Write-Host $(Temp)

Notice we are using the $(VariableName) format. This is very important. I often see people trying to access release variables as if they are PowerShell variables (omitting the parenthesis) which they are not. The name must be wrapped in parenthesis. Below is the log output from Stage 2.

2019-06-08T02:42:12.4564565Z Set In Stage 1
2019-06-08T02:42:12.4565202Z Created in Stage 1

Comments (16) -

  • Jason Gaylord

    6/10/2019 5:23:31 PM | Reply

    Thanks for posting this Donovan. So, if I wanted to get a value in an agent phase of a particular stage, would that value be present in an agentless phase for a REST call to the Azure API?

  • Vygis

    6/12/2019 10:51:54 AM | Reply

    I'm getting the following error when following the steps on AzD using HostedVS2017 agents:

    Invoke-RestMethod : {"$id":"1","innerException":null,"message":"VS402987: Deploy job 'first agent' in stage 'Stage 1' cannot be modified while it is in-progress. Changes were detected in the following properties: 'WorkflowTasks'.","typeName":"Microsoft.VisualStudio.Services.ReleaseManagement.Data.Exceptions.InvalidRequestException, Microsoft.VisualStudio.Services.ReleaseManagement2.Data","typeKey":"InvalidRequestException","errorCode":0,"eventId":3000}

    Is it actually possible to update variables when the release is in progress?

  • Stefan Stranger

    6/21/2019 1:18:27 PM | Reply

    I followed your steps but I'm getting the following error back:

    2019-06-21T13:16:05.4130580Z Invoke-RestMethod : {"$id":"1","innerException":null,"message":"VS402987: Deploy job 'Agent job' in stage 'Stage 1'
    2019-06-21T13:16:05.4131164Z cannot be modified while it is in-progress. Changes were detected in the following properties: 'WorkflowTasks'.","typeN
    2019-06-21T13:16:05.4131398Z ame":"Microsoft.VisualStudio.Services.ReleaseManagement.Data.Exceptions.InvalidRequestException, Microsoft.VisualStudio
    2019-06-21T13:16:05.4131552Z .Services.ReleaseManagement2.Data","typeKey":"InvalidRequestException","errorCode":0,"eventId":3000}
    2019-06-21T13:16:05.4131764Z At C:\Users\VssAdministrator\Documents\WindowsPowerShell\Modules\VSTeam\6.2.6\Private\common.ps1:625 char:12
    2019-06-21T13:16:05.4131911Z +    $resp = Invoke-RestMethod @params
    2019-06-21T13:16:05.4132052Z +            ~~~~~~~~~~~~~~~~~~~~~~~~~
    2019-06-21T13:16:05.4132216Z     + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
    2019-06-21T13:16:05.4132358Z    eption
    2019-06-21T13:16:05.4133298Z     + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

  • Carsten

    6/26/2019 10:51:17 AM | Reply

    Hi, why not use the "system" token?
    [x] Allow scripts to access OAuth token


    • Donovan

      7/14/2019 6:23:49 PM | Reply

      When I tried that the system token did not have permissions to change the values.

  • Swathi

    8/2/2019 10:38:28 AM | Reply

    Whenever I try to print the object "r" the output is very weird in html format.
    Due to which I am not able to update value for my release variable "test"
    Error is as below :
    2019-08-02T09:42:50.3977360Z The property 'value' cannot be found on this object. Verify that the property exists and can be set.
    2019-08-02T09:42:50.3977943Z At C:\agent\_work\_temp\a4044201-b1bc-411c-b05d-14242f16a704.ps1:5 char:1
    2019-08-02T09:42:50.3978131Z + $r.variables.test.value = 'Set In App 1'
    2019-08-02T09:42:50.3978227Z + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    2019-08-02T09:42:50.3978370Z     + CategoryInfo          : InvalidOperation: (Smile [], ParentContainsErrorRecordException
    2019-08-02T09:42:50.3978475Z     + FullyQualifiedErrorId : PropertyNotFound

  • MIchelle

    8/15/2019 2:28:29 PM | Reply

    Incase anyone else runs into the error:The string is missing the terminator: ".

    If you copy & pasted code from here, delete and re-type your dashes:

    This got me for a while so incase anyone else runs into it...

    • speedmind

      12/1/2019 6:52:09 AM | Reply

      Good catch !
      Took me a while, then came back to read the comments and boom...

  • Kevin Foley

    9/11/2019 2:50:21 PM | Reply

    I was also stuck on the "cannot be modified while it is in-progress" error reported by others.

    The problem appeared both when using the VSTeam library and Stefan's code - but only on certain projects.
    Projects that triggered the error had names that contained spaces or non-ascii characters
    Using Stefan's code, the fix for me was to use utf-8 encoding

    Invoke-RestMethod -Uri $releaseurl -Method Put -Body $json -ContentType "application/json;charset=utf-8" -Headers @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }

    The utf-8 issue is described here to address account names that have non-ascii characters.

    Thanks for the code Donovan and Stefan, this solved a big problem for our team

    • Saleel Kattiyat

      1/20/2021 12:03:02 PM | Reply

      This is a savior. This issue never came up for me until I started using variable groups. Probably the non-ascii characters got introduced as a result of that. More investigation needs to be done from my side. Happy that the solution works!!

  • Andreas

    9/20/2019 12:23:19 PM | Reply

    Thanks for the idea. I do not have the use case to transfer a variable from one stage to another, but transfer it to the next agent phase. Did someone test this?
    I see two potential problems:
    1. The release variables will only be fetched at the start of the release. (I am not sure)
    2. The created release variable will be fetched accidentally by another stage in the future. (then every stage has to remove this variable at the end again)

  • Keith Patton

    9/21/2019 4:36:56 AM | Reply

    Got excited about this, but then when trying it i get the same error as others noted above.

    Any ideas, can't seem to get this to work, in my instance i just want to pass variables in the same stage but across jobs.

    2019-09-21T04:32:15.6178890Z WARNING: VS402987: Deploy job 'FOO' in stage 'BAR' cannot be modified while it is in-progress. Changes were
    2019-09-21T04:32:15.6179864Z detected in the following properties: 'WorkflowTasks'.
    2019-09-21T04:32:15.6785823Z Invoke-RestMethod : {"$id":"1","innerException":null,"message":"VS402987: Deploy job 'FOO' in stage 'BAR' cannot
    2019-09-21T04:32:15.6786191Z be modified while it is in-progress. Changes were detected in the following properties: 'WorkflowTasks'.","typeName":"M
    2019-09-21T04:32:15.6786768Z icrosoft.VisualStudio.Services.ReleaseManagement.Data.Exceptions.InvalidRequestException, Microsoft.VisualStudio.Servic
    2019-09-21T04:32:15.6787037Z es.ReleaseManagement2.Data","typeKey":"InvalidRequestException","errorCode":0,"eventId":3000}
    2019-09-21T04:32:15.6787965Z At C:\Users\VssAdministrator\Documents\WindowsPowerShell\Modules\VSTeam\6.3.4\vsteam.functions.ps1:857 char:15
    2019-09-21T04:32:15.6789003Z +       $resp = Invoke-RestMethod @params
    2019-09-21T04:32:15.6789288Z +               ~~~~~~~~~~~~~~~~~~~~~~~~~
    2019-09-21T04:32:15.6790124Z     + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
    2019-09-21T04:32:15.6791362Z    eption
    2019-09-21T04:32:15.6792203Z     + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    2019-09-21T04:32:15.8032850Z ##[error]PowerShell exited with code '1'.
    2019-09-21T04:32:15.8488876Z ##[section]Finishing: Persist Release Variable Value copy

  • Morten Lerudjordet

    9/28/2019 8:18:50 AM | Reply

    Thanks for this, inspired me to do a write-up of one solution to do the same thing between Build and Release. Have been looking for a excuse to use the VSTeam module, and this gave me the perfect shoo-in.

  • William Randlett

    2/7/2020 8:13:19 PM | Reply

    I ended up just writing a text value to a file in the artifacts folder using PowerShell, and then reading the file back in from PowerShell and setting a local variable within the triggered pipeline.

  • Oskar Fjeld

    11/4/2020 1:59:07 PM | Reply

    Hi Donovan

    Great post. I'm getting an error though when trying to install VSTeam on my computer using Powershell 7.
    The module 'SHiPS' cannot be installed or updated because the authenticode signature of the file 'SHiPS.psd1' is not valid.

  • Meganathan

    3/31/2021 12:05:48 PM | Reply

    Hi Donovan
          I am trying to pass a variable "$hash" from one step to another step in Azure DevOps. The $hash contains Name,Hash and Length as NoteProperty. I was successful in passing the variable from one step to next step as $prop, but when i try to access $prop i am not able to access the NoteProperty of the variable.

        My question is if pass variable from one step to another step, How do i access the variables NoteProperty ??

Add comment