Update the Azure DevOps service endpoint (connection) using REST API

Copper Contributor

we are using the REST API Method (PUT) to update the existing AWS service connection in our ADO environment by assigning a minimum level of access (scopes) to the PAT.

The access levels are

  1. Service Connections (Read, query, and manage)
  2. Tokens (Read, update, and revoke)

There are no issues with this until past few days. We were able update the service connection on a scheduled basis using Azure Pipelines. But since past few days it started throwing 401 Unauthorized error. but it was working fine before. Not sure if they (Azure) have changed something in the latest release.

 

I tried to troubleshoot the issue by increasing the level of access scope one by one (assigned all the scopes at some point), but no luck with it. However, I was able to update the service connection, If I change the level of access to a full access instead of custom defined. But it is not a good idea to give the full level of access to a personal access token.

 

Am I missing something here or Is there a way to update the service connection with a minimum level of access control?

 

Also, what is difference between full access vs custom defined with all the scopes, since the full access is working fine, but custom defined with all the scopes is not working.

 

below is the snippet of code for your reference

 

$OrganizationName = "" 
$ProjectName = ""
$PAT = ""
$AccessKeyID = ""
$SecretAccessKey = "" 
$Serviceconnectionname = ""


function Update-AWSServiceConnection {

    Write-Host "Executing the Update Service Connection Script.."

    # Create the header to authenticate to Azure DevOps
    Write-Host "Create the header to authenticate to Azure DevOps"
    $token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($PAT)"))

    $Headers = @{
        Authorization = "Basic $token"
    }

    # Get the Project ID
    Write-Host "Construct the API URL to get the project ID.."
    $project = "https://dev.azure.com/" + "$OrganizationName/_apis/projects/$ProjectName ?api-version=6.0"
    Write-Host "Project API URL :: $project"
    try {
        Write-Host "Get the Project [$ProjectName] ID.."
        $response = Invoke-RestMethod -Uri $project -Headers $Headers -Method GET
        $ProjectID = $response.id
        if (!$ProjectID) {
            Write-Host "ProjectID value is null"
            Write-Error "Script step has been aborted." -ErrorAction stop
        } else {
            Write-Host "Project ID :: $ProjectID"
        }
    }
    catch {
        $ErrorMessage = $_ | ConvertFrom-Json
        throw "Could not Get the project [$ProjectName] ID: $($ErrorMessage.message)"
    }

    # Get Endpoint ID Details
    $endpoint = "https://dev.azure.com/" + "$OrganizationName/$ProjectName/_apis/serviceendpoint/endpoints?endpointNames=$Serviceconnectionname&api-version=6.0-preview.4"

    try {
        Write-Host "Get the Service Connection [$Serviceconnectionname] ID.."
        $response = Invoke-RestMethod -Uri $endpoint -Headers $Headers -Method GET
        $endpointId = $response.value.id
        if (!$endpointId) {
            Write-Host "Service Endpoint ID value is null"
            Write-Error "Script step has been aborted." -ErrorAction stop
        } else {
            Write-Host "Service Endpoint ID :: $endpointId"
        }

    }
    catch {
        $ErrorMessage = $_ | ConvertFrom-Json
        throw "Could not Get the service connection [$Serviceconnectionname] ID: $($ErrorMessage.message)"
    }

    # Create a body for the API call
    $url = "https://dev.azure.com/" + "$OrganizationName/_apis/serviceendpoint/endpoints/$endpointId ?api-version=6.1-preview.4"
    $body = @"
{
    "data": {},
    "id": "$endpointId",
    "name": "UpdatedServiceEndpoint",
    "type": "AWS",
    "url": "https://aws.amazon.com/",
    "description": null,
    "authorization": {
      "parameters": {
        "username": "$AccessKeyId",
        "password": "$SecretAccessKey"
        },
        "scheme": "UsernamePassword",
    },
    "isShared": false,
    "isReady": true,
    "owner": "Library",
    "serviceEndpointProjectReferences": [
      {
        "name": "$Serviceconnectionname",
        "projectReference": {
          "id": "$ProjectID",
          "name": "$ProjectName"
        }
      }
    ]
  }
"@

    try { 
    Write-Host "Updating the Service Connection [$Serviceconnectionname]"
    $response = Invoke-RestMethod -Uri $url -Headers $Headers -Method PUT -Body $body -ContentType application/json
    Write-Host "Connection Updated"
    $response
    }
    catch {
      Write-Host "An error occurred:"
      Write-Host $_
    }
    
}


Update-AWSServiceConnection

 

Any suggestions or comments would be greatly appreciated.

3 Replies

Having an issue with the ConvertFrom-json part. I get Invalid JSON primitive: Script. Any ideas?

Also, I get this:
Updating the Service Connection [Connection_Name_Here]
An error occurred:
{"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: endpoints","typeName":"System.ArgumentNullException, mscorlib","typeKey":"Argument
NullException","errorCode":0,"eventId":0}

@vinod-sunkara 

@vinod-sunkara Fixed both issues. There was an extra comma after "UsernamePassword" for the Convert-From-json error and I found that there was another permission to set for the account that my PAT was using to be an Administrator for the Service Connection which is why I was getting a NULL value for the Service Connection.

@JeffTech74 Hello Jeff, I am getting the same error, '401 Unauthorized', if you could, can you please give some details on how you resolved the second issue, i.e., the another permission to set for the account that PAT was using.