0
votes

Using the Azure DevOps REST API and PowerShell, I am trying to create a very basic Release pipeline. My JSON body works fine in Postman, but errors out when run with Invoke-RestMethod in PowerShell.

I'm following the documentation from https://docs.microsoft.com/en-us/rest/api/azure/devops/build/definitions/create?view=azure-devops-rest-5.0.

Using Postman, I've created a JSON body that works perfectly and repeatedly (provided I either change the release pipeline name or delete the previously created one). I've copied the JSON content verbatim to my PowerShell script, setting the variable $requestBody equal to the JSON content. When I run the script, I get an error (see below for error content).

Following is my test script (apologize for the length, but I thought it important I include the entire JSON.

$organization = "ORGNAME"
$token = "6-OBFUSCATED_TOKEN-a"
$project = "PROJECTNAME"

# Base64-encode the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $token)))

$uri = "https://dev.azure.com/$($organization)/$($project)/_apis/build/definitions?api-version=5.0"

$requestBody = '{
  "source": "restAPI",
  "revision": 1,
  "description": null,
  "name": "RepoName-CD",
  "path": "\\",
  "projectReference": null,
  "properties": {},
  "environments": [
      {
          "name": "Stage 1",
          "variables": {},
          "variableGroups": [],
          "preDeployApprovals": {
              "approvals": [
                  {
                      "rank": 1,
                      "isAutomated": true,
                      "isNotificationOn": false
                  }
              ],
              "approvalOptions": {
                  "requiredApproverCount": null,
                  "releaseCreatorCanBeApprover": false,
                  "autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
                  "enforceIdentityRevalidation": false,
                  "timeoutInMinutes": 0,
                  "executionOrder": "beforeGates"
              }
          },
          "postDeployApprovals": {
              "approvals": [
                  {
                      "rank": 1,
                      "isAutomated": true,
                      "isNotificationOn": false
                  }
              ],
              "approvalOptions": {
                  "requiredApproverCount": null,
                  "releaseCreatorCanBeApprover": false,
                  "autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
                  "enforceIdentityRevalidation": false,
                  "timeoutInMinutes": 0,
                  "executionOrder": "afterSuccessfulGates"
              }
          },
          "deployPhases": [
              {
                  "deploymentInput": {
                      "parallelExecution": {
                          "parallelExecutionType": "none"
                      },
                      "skipArtifactsDownload": false,
                      "artifactsDownloadInput": {
                          "downloadInputs": []
                      },
                      "demands": [],
                      "enableAccessToken": false,
                      "timeoutInMinutes": 0,
                      "jobCancelTimeoutInMinutes": 1,
                      "condition": "succeeded()",
                      "overrideInputs": {}
                  },
                  "rank": 1,
                  "phaseType": "agentBasedDeployment",
                  "name": "Agent job",
                  "refName": null,
                  "workflowTasks": []
              }
          ],
          "environmentOptions": {
              "emailNotificationType": "OnlyOnFailure",
              "emailRecipients": "release.environment.owner;release.creator",
              "skipArtifactsDownload": false,
              "timeoutInMinutes": 0,
              "enableAccessToken": false,
              "publishDeploymentStatus": true,
              "badgeEnabled": false,
              "autoLinkWorkItems": false,
              "pullRequestDeploymentEnabled": false
          },
          "executionPolicy": {
              "concurrencyCount": 1,
              "queueDepthCount": 0
          },
          "schedules": [],
          "retentionPolicy": {
              "daysToKeep": 30,
              "releasesToKeep": 3,
              "retainBuild": true
          },
          "processParameters": {},
          "properties": {},
          "environmentTriggers": []
      }
  ]
}'

Invoke-RestMethod -Uri $uri -Method POST -ContentType "application/json" -Headers @{Authorization = ("Basic {0}" -f $base64AuthInfo) } -Body $requestBody

When I run the script, I expected to get back the JSON confirming that the release pipeline was created, but instead I get the following error from PowerShell.

Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: definition.Repository","typeName":"System.ArgumentNullException, mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0} At C:\GitHub\landingzone\AzureDevOpsApiDev\testmule.ps1:113 char:1 + Invoke-RestMethod -Uri $uri -Method POST -ContentType "application/js ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Any assistance or guidance will be greatly appreciated.

2
I'm sure the first thing that's going to be pointed out is that I do not have an ID specified in the JSON. That is correct. I am trying to figure out why this seems to be fine in Postman, but not in my PowerShell script. Very strange.towerbe

2 Answers

0
votes

It looks like you're making a POST to the create build definition API. If you're trying to create a release definition, you probably need to post to a URL like this

POST https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions?api-version=5.0
0
votes

Well, the lesson here is to not copy and paste code from a previously working script WITHOUT DOUBLE CHECKING IT.

Mea Culpa.