DEV Community

Olivier Miossec
Olivier Miossec

Posted on

Getting started with Azure DevOps API with PowerShell

I use Azure DevOps every day for different kinds of clients, teams, and projects. I need to set up access, whenever I need Boards, Test Plans or other Azure DevOps services. I also need to decide how to configure the repository or the board. Sometimes I may have to import work items or initialize the wiki.
For some organization or some project, I also need to verify user configuration for compliance, security and license management.
These tasks are manual, time-consuming and I always forget to do one thing or another.

But there is a way to automate Azure DevOps Services set up, the Azure DevOps Rest API. This API lets you perform actions I mentioned and more. This short blog post will explain how.

Note, I will use PowerShell to operate, but you can choose the language of your choice. I use API version 5.1. The documentation can be found here

First, we need a way to authenticate to an Azure DevOps organization. There is two way to authenticate to Azure DevOps, using Azure Active Directory or using a Personal Access Token. It depends on the situation and on what you will need to build. For Azure Active Directory access you will need a client library (for .NET and PowerShell) or you can use Personal Access Token (PAT).

First, we need a way to authenticate to an Azure DevOps organization. There is two way to authenticate to Azure DevOps, using Azure Active Directory or using a Personal Access Token. It depends on the situation and on what you will need to build. For Azure Active Directory access you will need a client library (for .NET and PowerShell) or you can use Personal Access Token (PAT).

To create a Personal Access Token, login to Azure DevOps in this organization. On the right top corner click on the user icon.

PAT Icon

Select "Personal access tokens"

Then Click on "New Token". You will be asked to provide a name for the token, the expiration date, Organization Access, and the scope you want to apply, either all scopes or specify access for Work items, code (git repository), Build, Release, test and packaging.


Defining scope is important for your application; it defines how the application associated with the token will interact with Azure DevOps Services. Unless you are testing the API, never choose full access, review your needs and select the appropriate scopes.

After pushing the "Create" button, the token is displayed. Make sure to save the token securely, there is no way to retrieve it later!

To access Azure DevOps Service Rest API, we need to send a basic authentication header with every http request to the service. The basic authentication HTTP header look like

Authorization: basic

The credential needs to be Base64 encoded. In PowerShell you can do it like this.

$AzureDevOpsAuthenicationHeader = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($AzureDevOpsPAT)")) }
Enter fullscreen mode Exit fullscreen mode

Do not forget the extra white space between Basic and the “:”

Now that we know how to authenticate to Azure DevOps API, let’s see what we can do with the API.

We need first to build our URI. Using the API you will soon notice the different URI like or and many more. Most of the time, to be valid the URI needs to include, at least the organization name. or

Now, we can start to dig into the API. First, let's try to get a list of all projects within the organization.

Finally, we need to add "_apis" or

This will be our base URI for most operations.

Let’s start by getting the list of projects inside an organization.

$AzureDevOpsPAT = "ocd2rrtds7bj6mff6jcxjllmaaXXXXXXXXXXXXXXXXXXXXXXXX"

$AzureDevOpsAuthenicationHeader = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($AzureDevOpsPAT)")) }

$UriOrga = "$($OrganizationName)/" 
$uriAccount = $UriOrga + "_apis/projects?api-version=5.1"

Invoke-RestMethod -Uri $uriAccount -Method get -Headers $AzureDevOpsAuthenicationHeader 
Enter fullscreen mode Exit fullscreen mode

The API will return two elements. Count, the number of projects in the current organization and value, an array with the name, ID, visibility, revision, URI and last update time for each project.

Now how can we add a new project by using the rest API?

To create a project we need to provide a name, an optional description, visibility (private or public), a source control (Git or TFS) and the process model.
We need the process model ID and not only the name. This is because you can create your process model.

To get the process module ID, we must use another request to the API to get these ID.

$uriProcess = $UriOrga + "_apis/process/processes?api-version=5.1"
Invoke-RestMethod -Uri $uriProcess -Method get -Headers $AzureDevOpsAuthenicationHeader
Enter fullscreen mode Exit fullscreen mode

Now we can start to build the request body to add a project. For the process template I choose the Basic Process, b8a3a935-7e91-48b8-a94c-606d37c3e9f2.

$projectConfiguration = @{
        "name" = "TestProject"
        "description" = "Test Project"
        "ProjectVisibility" = "private"
        "capabilities" = @{
            "versioncontrol" = @{
                "sourceControlType" = "Git"
            "processTemplate" = @{
                "templateTypeId" = "b8a3a935-7e91-48b8-a94c-606d37c3e9f2"
}  | ConvertTo-Json -Depth 5

Invoke-RestMethod -Uri $uriProject -Method Post -Headers $AzureDevOpsAuthenicationHeader -Body $projectConfiguration -ContentType "application/json"
Enter fullscreen mode Exit fullscreen mode

The API does not create the project right away. Instead, it queues de request and response with a 202 Accepted HTTP code and 3 values, an ID on the request, a status (not set or queue most of the time) and a URI.

The last URI can be used to monitor the project creation.

We can now add users to this project. But we need first to list users currently in the organization. There are 3 kinds of users in an Azure DevOps organization, Azure Active Directory user, Microsoft Account user and build user (services). This is what you see in the organization settings.

$uriOrgaUsers = "$($OrganizationName)/_apis/userentitlements?api-version=5.1-preview.2"

(Invoke-RestMethod -Uri $uriOrgaUsers  -Method get -Headers $AzureDevOpsAuthenicationHeader).members
Enter fullscreen mode Exit fullscreen mode

With our user list, we can add them to the project we created in the last steps. We can not add members directly to the project. By default, when we created the project the Azure DevOps service create a default team, named after project name.

We can get the default Team ID by query the Project properties.

$UriOrga = "$($OrganizationName)/" 
$ProjectID = "576e2e9d-c7ee-4fd5-XXXXXXXXXX"

$uriProject = $UriOrga + "_apis/projects/$($ProjectID)/properties?api-version=5.1-preview.1"

(Invoke-RestMethod -Uri $uriProject -Method get -Headers $AzureDevOpsAuthenicationHeader).value
Enter fullscreen mode Exit fullscreen mode

We can add the user to this team by using the Team ID and one of the user IDs we collected.

$TeamID = "5a18ffd6-1f25-44b0XXXXXXXXXX"
$userID = "3fa53ee0-XXXXXXXXx"

$AddUserUri = "$($OrganizationName)/_apis/GroupEntitlements/$($TeamID)/members/$($userID)?api-version=5.1-preview.1"

Invoke-RestMethod -Uri $AddUserUri -Method put -Headers $AzureDevOpsAuthenicationHeader
Enter fullscreen mode Exit fullscreen mode

With the Azure DevOps Services Rest API, you can automate Projects, Teams creation, and onboarding. You can also create a git branch, a pull request or work items, and many other things.

The difficult part, as you may notice, the URL is not unified, and you may have to deal with API version and URI. You will need to follow the documentation and the internal logic of the product. But after a few tries, you will be able to what you need.

Top comments (10)

amolkhanorkar profile image
Amol Khanorkar

Hi Olivier,
I am getting error after executing below Invoke-restMethod,
Invoke-RestMethod -Uri $uriProject -Method Post -Headers $AzureDevOpsAuthenicationHeader -Body $projectConfiguration -ContentType "application/json"

Below is the error mesaage:
Invoke-RestMethod : Invalid URI: The hostname could not be parsed.
At line:1 char:1

  • Invoke-RestMethod -Uri $uriProject -Method Post -Headers $AzureDevOps ...
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    • CategoryInfo : NotSpecified: (:) [Invoke-RestMethod], UriFormatException
    • FullyQualifiedErrorId : System.UriFormatException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Please help me resolve this error so I can try to create a Project and go-ahead.

paulsisaac profile image
Paul isaac

I am confused as to how this works for some people. The $uriProject variable is created using the ProjectID, which is hardcoded in the script $ProjectID = "576e2e9d-c7ee-4fd5-XXXXXXXXXX". I am assuming this is not correct and it only comes further down in the script after the $UriProject is queried.
As such this line (Invoke-RestMethod -Uri $uriProject -Method get -Headers $AzureDevOpsAuthenicationHeader).value fails as there is no value for $uriProject.

Am I looking at this right, later on, further down $projectID is defined as a hardcoded variable and then $uriproject is created using the $ProjectID

$uriProject = $UriOrga + "_apis/projects/$($ProjectID)/properties?api-version=5.1-preview.1"

But how do we get the Project ID in the first place?

alexia19apl profile image

Hi Olivier, what an incredible and working article (tested, and yeah it works),
Could be applied this concept to Wikis, I mean to retrieve data from a wiki or the other possible case to place data a wiki?

rr9853462 profile image
Rima Sharma

Great post! This is a great starting point for anyone looking to get started with Azure DevOps API and PowerShell. The combination of cloud and DevOps is so powerful and this post does a great job of showing how to leverage them together. Highly recommend checking it out.

ayanmullick profile image
Ayan Mullick

Is it possible to pass the token in the URL? I'm trying to use a URL to create an AzMonitor Action Group Webhook that would create an ADO task when an alert is triggered. However, the webhook needs the token in the URL.

Authenticate the webhook for activity log alerts

revanthkariappa profile image
Revanth Kariappa K R • Edited

which is the default team id
System.CurrentProcessTemplateId cc94d82xxxxxxxxxdc6557bf
System.OriginalProcessTemplateId cc92xxxxxxxxxxxxxx-a22557bf
System.ProcessTemplateType b8a3a93xxxxxxxxxxxc-63e9f2
System.MSPROJ <?xml version="1.0" encoding="utf-8"?>...
System.Process Template Scrum
System.Microsoft.TeamFoundation.Team.Count 1
System.Microsoft.TeamFoundation.Team.Default e469xxxxxxxxxxxxx072f867
System.SourceControlCapabilityFlags 2
System.SourceControlGitEnabled True
System.SourceControlGitPermissionsInitialized True
System.Wiki.57985xxxxxxxxxxxxxxe53 {"id":"5xxxxxxxxxxxx06-9e53","versions":[{"Version":"wikiMaster"}],"type":0,"...

arulmouzhi profile image

Hi Olivier Miossec,
I have followed the above things and it works well. But my case is - Delete the bulk set of test cases through PowerShell. I have also checked MS Doc reg this - . Bulk deletion is not supported at present from a query results page. So, I have to do it by using either .net or powershell. By reading the above article, i am little bit good and familiar with powershell. but it throws error for me when i tried bulk delete test case. Can you help me reg this. i have posted this as question here -

sudalaikumar1624 profile image

Using API, How to get the latest code from TFVC repo in Azure Devops ? Example
Thanks in advance!

ravidsinghbiz profile image
Ravi D. Singh

Do you use the terraform for any azure devops automation?

roua99 profile image

Hi, I had this error in the step when creating project Configuration

Invoke-RestMethod : {"count":1,"value":{"Message":"The requested resource does not support http method 'POST'."}}