0
votes

I have an Azure Pipelines variable group with tree variables defined in "Library". I want to update one of the values from my pipelines.

I have written this Powershell script to do so.

$variableName = "Version_old"
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/distributedtask/variablegroups/4?api-version=5.1-preview.1"

$authHeader = @{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
$definition = Invoke-RestMethod -Uri $url -Headers $authHeader

$oldValue = $definition.variables.$variableName.Value
Write-Host "Using old value:" $oldValue

$array = $oldValue.Split(".")
$newValue = $array[0] + "." + $array[1]+"." +  ([int] $array[2] + 1) 
Write-Host "Updating new value:" $newValue

$definition.variables.$variableName.Value = "$($newValue)"
$definitionJson = $definition | ConvertTo-Json -Depth 100 -Compress
Invoke-RestMethod -Method Put -Uri $url -Headers $authHeader -ContentType "application/json" -Body ([System.Text.Encoding]::UTF8.GetBytes($definitionJson)) | Out-Null

When I run this from a build pipeline, everything works as intended - the variable is updated.

When I extract the JSON from the URI created above, I get this:

{
    "createdBy": {
        "displayName": "<redacted>",
        "id": "guid",
        "uniqueName": "<redacted>"
    },
    "createdOn": "2020-12-16T02:21:48.65Z",
    "id": 4,
    "isShared": false,
    "modifiedBy": {
        "displayName": "MyTeam Build Service (myorg)",
        "id": "<redacted>",
        "uniqueName": "Build\\<redacted>"
    },
    "modifiedOn": "2021-03-14T19:55:34.1466667Z",
    "name": "MyTeam",
    "type": "Vsts",
    "variableGroupProjectReferences": [
        {
            "name": "MyTeam",
            "projectReference": {
                "id": "<redacted>",
                "name": "MyTeam"
            }
        }
    ],
    "variables": {
        "API": {
            "value": "0.8.8"
        },
        "UI": {
            "value": "0.7.13"
        },
        "Version_old": {
            "value": "10.0.19"
        }
    }
}

However - when I do a verbatim copy of the script and add it as a Task in a Release pipeline, it fails.

When I add these lines to the script

Write-Host "JSON content from REST API:"
Write-Host $definition.variables.API.value
Write-Host $definition.variables.UI.value
Write-Host $definition.variables.Version_old.value

The result is this in the build pipeline:

2021-03-14T21:15:35.8686524Z JSON content from REST API:
2021-03-14T21:15:35.8769811Z 0.8.9
2021-03-14T21:15:35.8828202Z 0.7.13
2021-03-14T21:15:35.8863094Z 10.0.22
2021-03-14T21:15:35.8912583Z Using old value: 10.0.22
2021-03-14T21:15:35.9233459Z Updating new value: 10.0.23

But this in the release pipeline:

2021-03-14T21:17:42.7708488Z JSON content from REST API:
2021-03-14T21:17:42.7833228Z 
2021-03-14T21:17:42.7863873Z 
2021-03-14T21:17:42.7890923Z 
2021-03-14T21:17:42.7954203Z Using old value: 
2021-03-14T21:17:42.9884159Z You cannot call a method on a null-valued expression.
2021-03-14T21:17:42.9885985Z At C:\agent\_work\_temp\869a5459-3622-464a-9f6e-f20fb6ac1020.ps1:20 char:1
2021-03-14T21:17:42.9886600Z + $array = $oldValue.Split(".")

(I have not added the three more-or-less blank lines)

More debug information:

When I modify the script to pipe the $definition variable to the output like this:

$definition = Invoke-RestMethod -Uri $url -Headers $authHeader
Write-Host "JSON content from REST API:"
Write-Host $definition

This is the result from my build pipeline:

2021-03-14T21:28:25.5046100Z JSON content from REST API:
2021-03-14T21:28:25.5109539Z @{variables=; id=4; type=Vsts; name=MyTeam; createdBy=; createdOn=2020-12-16T02:21:48.65Z; modifiedBy=; modifiedOn=2021-03-14T21:15:35.96Z; isShared=False; variableGroupProjectReferences=System.Object[]}

And this is the result from my release pipeline:

2021-03-14T21:31:50.5474731Z JSON content from REST API:
2021-03-14T21:31:50.5478033Z @{id=4; name=MyTeam; isShared=False; variableGroupProjectReferences=}

Configuration of the release job:

My configuration is this. The "Allow scripts to access the OAuth token" was already ticked off.

enter image description here

So something is clearly different. The exact same lines produce different output depending on whether it is run from the build pipeline or the release pipeline.

What I am doing wrong?

I have configured the build pipeline and the release stage exactly the same. I have linked the variable group in the same way. In the "Release pipeline" I have configured the scope of the variable group link to "Stages --> my stage". Everything seems to be set up correctly ... but it does not work.

Thank you :-)

1
Appeantly $oldValue is not string but a $Null (or doesn't exist at $definition.variables.Version_old.Value) , please share the retrieved json ($definition) content.iRon
Hi @iRon thank you for your comment. I have added a bunch of additional debug information. I can see that the .Split() method fails due to a NULL value. But I do not understand why the script produces a valid value in the build pipeline and a NULL value in the release pipeline. Thank you :-)Jesper Lund Stocholm

1 Answers

1
votes

I test your ps file and I reproduce this issue and solve it in the Release. Please check your release job and make sure your have checked the 'Allow scripts to access the OAuth token'. Attach my test result: enter image description here enter image description here

Update:

You can try to check your release security, please make sure you have add the Project Collection Build Service user into your release: enter image description here

And in your variable group security, you can check if you have set the Project Collection Build Service user Admin access: enter image description here

You issue seems about the OAuth Token using issue in the release, so we can also try to create a new PAT token and use it in the PS script:

$token = "xxxxxxx"

$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))

$response2 = Invoke-RestMethod -Uri $urlIds -Headers @{Authorization = "Basic $token"} -Method Post -Body $JSON -ContentType application/json