Change variable group value of Azure Pipeline - azure

I have a Variable Group in Azure Pipeline(below attached),
I want to change the value of isPOS to False through below mentioned conditions,
$angular = (Get-Content "$(system.defaultworkingdirectory)/amaze-commerce/angular.json" -Raw) | ConvertFrom-Json
if ($angular.defaultProject -ne "ecomm-ac-ecomm"){
// Please add your code here
}
Can you please guide me to change the Variable group value and i want to use the same in Release Pipeline.

In order to change the value of a variable group use Azure DevOps Api.
An example of how to update a variable group:
Variablegroups - Get Variable Groups - filtered by {groupName}
$pat ="<your-tfs-security-token>"
$read = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$pat"))
$variableGroupName = "Check for angular.json"
$variableGroupId = ((Invoke-RestMethod -Method Get -Headers #{'Authorization' = "Basic $read" } -Uri "https://{instance}/{collection}/{project}/_apis/distributedtask/variablegroups?groupName=${variableGroupName}").Value).id
Variablegroups - Update
$body =#"
{
"variables": {
"isPOS": {
"value": $false
}
},
"type": "Vsts",
"name": "${variableGroupName}",
"description": "Updated variable group"
}
"#
$response= (Invoke-RestMethod -Uri "https://{instance}/{collection}/{project}/_apis/distributedtask/variablegroups/${variableGroupId}?api-version=5.0-preview.1" -Method Put -Headers #{'Authorization' = "Basic $read" } -ContentType "application/json" -Body $body)

Related

What causes "invalid query definition, dataset is invalid or not supplied" querying the Azure REST API with powershell?

I've tried multiple ways to get cost management information from the Azure REST API using Powershell. I'm copy/pasting the data for my $body variable directly from their documentation. I get this error with every example they've posted.
Below is my original attempt.
I've tried to pipe $body to convertto-json.
I've tried saving it as a .json file and then using get-content -raw to get it.
I've tried defining everything in a $params hash table and then using invoke-restmethod #params
No matter what I get the same error.
invalid query definition, dataset is invalid or not supplied
$method = "post"
$URI = "https://management.azure.com//subscriptions/12345678-1234-1234-1234-1234556789123/resourceGroups/HubRG/providers/Microsoft.CostManagement/query?api-version=2019-11-01"
$headers = #{
"authorization" = "Bearer verylongstringofcharacters"
}
$body = #"
{
"type": "ActualCost",
"dataset": {
"granularity": "Daily",
"aggregation": {
"totalcost" : {
"name": "cost",
"function": "Sum"
}
},
"grouping": [
{
"type": "Dimension",
"name": "ResourceGroup"
}
]
}
}
"#
Invoke-RestMethod -Method $method -URI $URI -Headers $headers -Body $body
I had this same issue - drove me crazy for at least an hour. It turned out that even though I was using Invoke-RestMethod, I had to explicitly set 'Content-Type' = 'application/json' in the headers of the request. Without it: 'Dataset is invalid...', with it: success.
$headers = #{
"authorization" = "Bearer verylongstringofcharacters"
"Content-Type" = "application/json"
}

How to create Azure DevOps Library Variable Group using the data from json/csv file?

[1]Can someone please help me on how to create variable group in Azure DevOps Library using PowerShell? The file is in .json/.csv file. This is what I have so far. I am new to PowerShell so please excuse any errors.
$file = get-content = C:\test\Variables.json
ForEach {
$name = $_.Variable;
$Issecret = $_.IsSecret;
$Value = $_.Value;
az pipelines variable-group create --name test -p $ProjectName --org $orgUrl --authorize --variables -$name -$issecret -value
}
I am trying to import all the values to Azure DevOps library.
Name Is Secret Value
-------------------------- ----------- -------------------------------------------------------------------------------
Test1 False https://test1.com
Test2 False https://test2.com
You can get data from the csv file through the script below:
$body=#{
"variables"= #{};
"type"= "Vsts";
"name"= "TestVariableGroup1";
"description"= "A test variable group"
}
$employee_list = Import-Csv "D:\test\data.csv"
foreach ($employee in $employee_list){
$body.variables[$employee.name]=#{value=$setting.value; isSecret=$employee.isSecret}
}
$body | ConvertTo-Json
Then you can use rest api to create variable group.
Request url:
POST https://dev.azure.com/{organization}/_apis/distributedtask/variablegroups?api-version=6.0-preview.2
Request body:
{
"description": "xxxx",
"name": "xxx",
"providerData": null,
"type": "Vsts",
"variables": {"test1": {
"isSecret": true,
"value": "fortest1"
},
"test2": {
"isSecret": true,
"value": "fortest2"
}},
"variableGroupProjectReferences": [{
"description": "xxxx",
"name": "xxx",
"projectReference": {
"id": "projectId",
"name": ""
}
}]
}
Sample script:
$token = "PAT token"
$url = "https://dev.azure.com/{organization}/_apis/distributedtask/variablegroups?api-version=6.0-preview.2"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$JSON = #'
request body
'#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -ContentType application/json -body $JSON

Updating Azure DevOps Release Pipeline Variable During Release

I have a classic Release Pipeline that has a few custom variables set that are used periodically throughout the release.
The first two steps in the release are two PowerShell scripts. In the first one, I basically take one of the variables, and assign a value to it. I then output what the variable was updated to so I can make sure it is correct (it always is). The second script does basically the same thing but to a different variable, and when I output the value, it is always correct.
Now, as the release is going, if I switch to the Variables tab, I can see the variable was never updated. It is still set at the value from the previous release. This is a major issue for me because about half way down the release, I have a "Copy Files" step, where it copies files to a folder path that is created from those variables. Since the variables are from the previous release, they are put into an improperly named folder path.
After the release pipeline is completed finished and succeeds, the Pipeline Variables are then correctly updated on the Variables tab.
Is there a way that I can update these variables DURING the release, instead of them updating after the release has completed? I would prefer to update them properly in my PowerShell scripts, or as a setting in the pipeline.
This is basically what my scripts looks like:
$url = "$($env:SYSTEM_TEAMFOUNDATIONSERVERURI)$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.0-preview.3"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
$buildNumber = $env:BUILD_BUILDNUMBER
$pipeline.variables.ReleaseVersion.value = $buildNumber
####****************** update the modified object **************************
$json = #($pipeline) | ConvertTo-Json -Depth 99
$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
write-host "================================="
write-host "The value of ReleaseVersion updated to " $updatedef.variables.ReleaseVersion.value
write-host "================================="
My variable (ReleaseVersion in the script above) is set in the Variables tab, it's scope is 'Release', and 'Settable at release time' is checked. I have also tried using Write-Host '##vso[task.setvariable variable=ReleaseVersion]$(Build.BuildNumber)' to set my variable, but I get the same outcome.
UPDATE
ADDING NEW SCRIPT AND LOG DESCRIPTION
So I just pushed new code through my pipeline. The build was numbered v2.1.0.16 (which is correct). I have the build number set to the branch name, plus a (:.rev) variable at the end.
The first script in the pipeline sets a custom pipeline variable called ReleaseVersion. It is set to the build number. This is the script:
$url = "https://vsrm.dev.azure.com/{organization}/$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.0-preview.3"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
$buildNumber = $env:BUILD_BUILDNUMBER
$pipeline.variables.ReleaseVersion.value = $buildNumber
####****************** update the modified object **************************
$json = #($pipeline) | ConvertTo-Json -Depth 99
$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
write-host "================================="
write-host "The value of ReleaseVersion updated to " $updatedef.variables.ReleaseVersion.value
write-host "================================="
and my output:
2020-05-11T03:02:21.5631557Z "id": #,
2020-05-11T03:02:21.5632209Z "name": "#",
2020-05-11T03:02:21.5632816Z "path": "#",
2020-05-11T03:02:21.5633410Z "projectReference": null,
2020-05-11T03:02:21.5634223Z "url": "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}",
2020-05-11T03:02:21.5635058Z "_links": {
2020-05-11T03:02:21.5635643Z "self": {
2020-05-11T03:02:21.5636500Z "href": "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}"
2020-05-11T03:02:21.5637445Z },
2020-05-11T03:02:21.5641618Z "web": {
2020-05-11T03:02:21.5643197Z "href": "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}"
2020-05-11T03:02:21.5644085Z }
2020-05-11T03:02:21.5647518Z }
2020-05-11T03:02:21.5648322Z }
2020-05-11T03:02:22.4291104Z =================================
2020-05-11T03:02:22.4456531Z The value of ReleaseVersion updated to v2.1.0.15
2020-05-11T03:02:22.4483349Z =================================
2020-05-11T03:02:23.0643676Z ##[section]Finishing: Update Release Version
It says the value has been updated to v2.1.0.15, which is one revision behind the current build. I then have a script to make a folder path based on the above variable. It checks for a folder with that name (v2.1.0.15 for example), and will attach a -1 if it was already found, and a -2 if the -1 was already found, and so-on. It sets that folder name to a custom pipeline variable called RootDirectory. This is the script:
$url = "https://vsrm.dev.azure.com/{organization}/$env:SYSTEM_TEAMPROJECTID/_apis/Release/definitions/$($env:RELEASE_DEFINITIONID)?api-version=5.0-preview.3"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
write-host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
$rootDirectory = $pipeline.variables.BuildDirectory.value + "\" + $pipeline.variables.ReleaseVersion.value
if (test-path $rootDirectory) {
$newDirectory=$rootDirectory
$index=0
while (test-path $newDirectory) {
$index += 1
$newDirectory=$rootDirectory + "-" + $index
}
}
$pipeline.variables.RootDirectory.value = $newDirectory
####****************** update the modified object **************************
$json = #($pipeline) | ConvertTo-Json -Depth 99
$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
write-host "================================="
write-host "The value of Root Directory updated to " $updatedef.variables.RootDirectory.value
write-host "================================="
The BuildDirectory variable is a hardcoded variable that never changes. And it's output:
2020-05-11T15:32:45.7255688Z "id": #,
2020-05-11T15:32:45.7255852Z "name": "#",
2020-05-11T15:32:45.7256001Z "path": "#",
2020-05-11T15:32:45.7256166Z "projectReference": null,
2020-05-11T15:32:45.7256379Z "url": "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}",
2020-05-11T15:32:45.7256556Z "_links": {
2020-05-11T15:32:45.7256698Z "self": {
2020-05-11T15:32:45.7256903Z "href": "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}"
2020-05-11T15:32:45.7257174Z },
2020-05-11T15:32:45.7257331Z "web": {
2020-05-11T15:32:45.7257537Z "href": "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/definitions/{definitionId}"
2020-05-11T15:32:45.7257721Z }
2020-05-11T15:32:45.7257862Z }
2020-05-11T15:32:45.7258016Z }
2020-05-11T15:32:46.6474274Z =================================
2020-05-11T15:32:46.6481861Z The value of Root Directory updated to
2020-05-11T15:32:46.6491120Z =================================
2020-05-11T15:32:46.7209281Z ##[section]Finishing: Create Root Directory
Notice how the output of that script is blank, it does not show what the variable was updated to.
A few steps later in my pipeline, is where I actually use those variables. It is in a "Copy files" pipeline task. The target folder is set to $(RootDirectory)/Debug, but since the RootDirectory variable isn't updated, it just copies the files to the root c: drive.
When I used code above with REST API ReleaseVersion remained the same as it was. However, I used logging command Write-Host '##vso[task.setvariable variable=ReleaseVersion]$(Build.BuildNumber)' and ReleaseVersion was updated but a new value was available in next step. So the new value should be available in Copy Files as it is a next step.
Updating Azure DevOps Release Pipeline Variable During Release
First, the reason why the logging command not work for you is that:
The variable set by the logging command can only be used inside the current agent, and will not modify the value of the web potral variable.
So, we could use the set variable in the next task, but if you want to update the variable on the Variables tab, you could use the REST API (Definitions - Update) to update the value of the release definition variable from a release pipeline:
PUT https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions/{definitionId}?api-version=5.0
Then, I have checked your scripts, it is close to the correct answer. The reason why it doesn't work for you is that you use variable $($env:SYSTEM_TEAMFOUNDATIONSERVERURI) in your url.
The default value of that variable is https://dev.azure.com/YourOrganization/. However, the API we use is that https://vsrm.dev.azure.com/{organization}, missing vsrm in the Url.
You could check my previous thread for some more details.
Hope this helps.

Azure DevOps Rest API to create a branch from a specific branch

I'm looking for an Azure DevOps Rest API to create a new branch from an existing branch.
Azure DevOps Rest API to create a branch from a specific branch
Konteks pointed out the correct REST API.
We could use the Initial commit (Create a new branch) to create a branch, but if you want to create a branch from a specific branch, we need modify the Request Body.
POST https://dev.azure.com/fabrikam/_apis/git/repositories/{repositoryId}/pushes?api-version=5.1
First, we need use the REST API Repositories - List to get the repositoryId.
GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories?api-version=4.1
Then, use the REST API Refs - List with filter=<BranchName> to get the oldObjectId for your specific branch:
GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/refs?filter=heads/master&api-version=5.1
Now, we could use the REST API Repositories - List with following request body to create a new branch from a specific branch:
{
"refUpdates": [
{
"name": "refs/heads/<DefineYourNewBranchName>",
"oldObjectId": "<oldObjectId we get from above REST API>"
}
],
"commits": [
{
"comment": "Initial commit.",
"changes": [
{
"changeType": "add",
"item": {
"path": "/readme111.md"
},
"newContent": {
"content": "My first file!",
"contentType": "rawtext"
}
}
]
}
]
}
Result from postman:
This is my test powershell scripts:
$connectionToken="<PAT Here>"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$headers = #{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" }
$url= "https://dev.azure.com/<Organizationname>/<ProjectName>/_apis/git/repositories/<repositoryId>/pushes?api-version=5.1"
$body =#"
{
"refUpdates": [
{
"name": "refs/heads/Test228",
"oldObjectId": "a57f0c34f8ec7330bdc37e7631f7be3cc3ea3956"
}
],
"commits": [
{
"comment": "Initial commit.",
"changes": [
{
"changeType": "add",
"item": {
"path": "/readme111.md"
},
"newContent": {
"content": "My first file!",
"contentType": "rawtext"
}
}
]
}
]
}
"#
Write-Host "$url"
$response= Invoke-RestMethod -Uri $url -ContentType "application/json-patch+json" -Body $body -headers #{authorization = "Basic $base64AuthInfo"} -Method POST
Hope this helps.
I captured the requests created by the AzureDevOps web UI and found out that creating a branch from a specific branch is quite simple task for the REST api.
$repository = "repositoryName"
$newBranch = "newBranchName"
$baseBranch = "baseBranchName"
$organization = "organizationName"
$project = "projectName"
$pat = "personalAccessToken"
$base64AuthInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$pat"))
$headers = #{ Authorization = "Basic $base64AuthInfo" }
# Get ID of the base branch
$url = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repository/refs?filter=heads/$baseBranch&api-version=5.1"
$baseBranchResponse = Invoke-RestMethod -Uri $url -ContentType "application/json" -headers $headers -Method GET
# Create a new branch
$url = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repository/refs?api-version=5.1"
$body = ConvertTo-Json #(
#{
name = "refs/heads/$newBranch"
newObjectId = $baseBranchResponse.value.objectId
oldObjectId = "0000000000000000000000000000000000000000"
})
$response = Invoke-RestMethod -Uri $url -ContentType "application/json" -Body $body -headers $headers -Method POST
This worked for me:
To create/update/delete:
https://learn.microsoft.com/en-us/rest/api/azure/devops/git/refs/update%20refs?view=azure-devops-rest-5.0#create/update/delete-a-ref-by-repositoryid
To get objectId:
https://learn.microsoft.com/en-us/rest/api/azure/devops/git/refs/list?view=azure-devops-rest-5.0#refs
https://learn.microsoft.com/en-us/rest/api/azure/devops/git/pushes/create?view=azure-devops-rest-5.1#initial-commit-(create-a-new-branch)
See section "initial commit"
Sparrow plugin does what you need ( using Rest API ):
s6 --plg-run ado-git-branch-create#project=Backends,repo=Catalog,branch_from=dev,branch=feature
Please pay attention, it does not create any dummy files for that, it only references for an existing branch through it's internal object ID.
Feel free to still the code ;-)).
PS Disclosure. I am the tool author, more details could be found here - https://github.com/melezhik/Spazure

Azure DevOps REST API returns a 403 when using the system OAuth token during a build

I'm running a script:
# Variables
$organization = "****"
$project = "****"
$repositoryId = "****"
$pullRequestId = $env:BUILD_PULLREQUEST_ID
$pat = "Bearer $env:System_AccessToken"
$featureReleaseUrl = "http://" + $env:prSourceBranchName + ".azurewebsites.net"
$body = #"
{
"comments": [
{
"content": "Link naar feature release $featureReleaseUrl"
}
]
}
"#
$createThreadInPRUrl = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repositoryId/pullRequests/$pullRequestId/threads?api-version=5.0"
if ($pullRequestId) {
Invoke-RestMethod -Uri $createThreadInPRUrl -Headers #{Authorization = $pat} -Body $body -Method Post -ContentType 'application/json'
}
When it runs it returns a:
##[error]The remote server returned an error: (403) Forbidden.
I've created a Personal Access Tokens in my personal settings.
I've also created this script:
# Variables
$organization = "****"
$project = "****"
$buildId = $****
$pat = "Bearer $env:System_AccessToken"
if (!$env:Build_PullRequest_SourceBranchName) {
$retrieveSourceBranchFromBuildURL = "https://dev.azure.com/$organization/$project/_apis/build/builds/$buildId" + "?api-version=5.0"
$buildInformation = Invoke-RestMethod -Uri $retrieveSourceBranchFromBuildURL -Headers #{Authorization = $pat } -Method Get -ContentType 'application/json'
$SourceBranchFromBuild = $buildInformation.sourceBranch.split('/')[-1]
Write-Host "### no Build PullRequest SourceBranchName available ###"
Write-Host "##vso[task.setvariable variable=prSourceBranchName;]"$SourceBranchFromBuild
}
And this runs fine. The difference between the first and second script is that the first is a POST and the second a GET. But they both use the $pat token.
Even though the token you used is System.AccessToken, if you don't have access permission of Pull Request, you will also could not operate it.
Go Project Setting--> Repositories--> Repository you want to access, locate your account or the group you are in. Check the permission state of Contribute to pull requests.
You must have this Contribute to pull requests permission allowed, so that you can add the comment to PR.

Resources