Azure DevOps

Automate Azure DevOps like a boss

Over the past weeks, I have worked on automation within Azure DevOps. One of the tasks was to create a self-service tool for our developers to create new projects where all pre-requisites were taken care of. That means the project itself, service connections (ARM) to access our Azure Kubernetes Service (AKS), Azure AD groups for accessing the project, and so on.

For the Azure AD part, I had mostly everything in place already. Service connections for Azure AD are essentially Azure application registrations, and Azure AD groups are easily created using New-AzADGroup or Microsoft Graph API. However, my experience with Azure DevOps API was and still is limited.

Creating the project

Creating the project itself is pretty straightforward. Below is a PowerShell snippet to do so. I used a service account and a Personal Access Token (PAT) with the following access permissions to do everything in my code.

  • Graph, read/manage
  • Identity, read/manage
  • Member Entitlement Management, read/write
  • Project and team, read/write/manage
  • Security, manage
  • Service connections, read/manage/query

Assigning permissions using Azure DevOps API

You don’t get far with just a project. Someone needs to have access to it as well. Since I try to create a paved road for the DevOps users I needed to add users to the DevOps groups inside the project. Here I spent some significant time, trying to understand how. In my routine, I already create three AAD groups for Project Administrators, contributors, and readers. We want to have one single pane for managing access to company resources, and Azure AD is the place.

In my opinion, access control in Azure DevOps is a nightmare, but lets not focus on that. I want to add each AAD group in to it’s corresponding Azure DevOps group.

To do that you use Azure DevOps Graph and the Groups endpoints. What you can see in the Microsoft example is that you need to perform a post operation against{organization}/_apis/graph/groups?groupDescriptors=vssgp.Uy0xLTktMTU1MTM3NDI0NS0yMTc2MDU2ODQ4LTMyODAwNzczODUtMjM4NDQzMDA4Mi0yNTc3Njk3NTA4LTEtNzM0NDQ1NzM2LTQwNzkyNzIyNjgtMzA0NzY5MjIyMy0yMjg2NTY0ODM0&api-version=6.1-preview.1

Azure DevOps Descriptor

From the documentation, you can see the request to add AAD groups into a project group like Project Administrators you need to specify a groupDescriptor. I could not find any good information on how to get this information, and as you can see, the request does not specify the project, only at the organization level.

Now, after some digging, I figured I could fetch this information with some additional calls to the API.

  1. Get your project descriptor, by using the projectId as your descriptor…
  2. Get all groups within the project, using the actual project descriptor
  3. Filter the groups you want from the above request
  4. Pass the Azure AD group objectId in the body and POST against /graph/groups?groupDescriptors=

Modify Azure DevOps project features

In our case, we do not use all features in Azure DevOps. I, therefore, wanted to turn off some features like boards. Making it a bit more difficult for our developers to start using features that we have other tools to support. I couldn’t find any official endpoint documented, so I reached out on Twitter to get inputs. Of course fellow MVP Rob Bos had some time to inspect the portal calls and came up with the solution. Basically, after the project is created, you need to make additional calls to an old API to flip the switch for each feature you do not use.

Adding ARM service connections to project using DevOps API

This part is quite well documented. So after creating the app registrations and service principals in Azure AD. You need to create the service connection(s) in the project. In my case I had more than one service connection, so I had to run this snippet multiple times, as I could not find a batch operation for it.

I think that pre-provisioning of the service connections are a good idea. This feature is quite complex to grasp for many, as the built in wizard cause more confusion than it helps. Especially when the users try to create a new SC, and they do not have access to create App registrations in Azure, or to set permissions on the subscription. Then the entire wizard will fail, but you might end up with ghost SPNs in Azure…

I said it was properly documented, but if you take a close look. The endpoint is called servicendpoint and not serviceconnection which is what it is called in the portal.

Automation solutions for Azure DevOps

In my examples I use the native Azure DevOps APIs and PowerShell. This worked best in our solution. However, you can also use Azure CLI or Azure DevOps provider for Terraform.

Since we do not use Terraform for any IAC, I weren’t keen to start using it just for Azure DevOps. Azure CLI have some limitations since it only allow interactive login, or a semi-solution for the PAT. I suggest you see what solution that works for you. But my examples above do at least work.


In this post I showed how I solved Azure DevOps project creation. The code above only show half the solution as it is very domain specific. However, I hope it helps you along the way. Creating the actual project is only one part of it. You need to create a paved road for the users. Therefore, make sure the users are able to access their projects and deploy resources. Automating the setup will ensure that every project is set up equally and supporting future requests from your developers will be much easier.

  • puravive reviews

    Ive read several just right stuff here Certainly price bookmarking for revisiting I wonder how a lot effort you place to create this kind of great informative website

  • gate io para çekme

    This article opened my eyes, I can feel your mood, your thoughts, it seems very wonderful. I hope to see more articles like this. thanks for sharing.

  • David Pazdera

    Thanks for an interesting article, Martin. I was wondering if you considered using the VSTS PowerShell module for some parts of the workflow. You are using PSH anyway, so this could simplify your solution. The name of the module is a bit misleading, it does work with ADO and it is continuously updated:

    1. Martin Ehrnst

      Hi David. I did look at it earlier. But I was a bit confused regarding authentication here as well. But from what I see here, it should definitely be considered.

      I just put my script into a pipeline now, so then I do not need to care about modules, etc. But yes, it would probably be easier with the module 🙂

  • qubert

    We could achieve much the same thing with Terraform too.

    Im not trying to denigrate what you have written. In fact, its all great stuff. Its just in my time working within a DevOps culture and automating workflows, pipelines CI/CD etc. Terraform has played a big part in IaC and is a familiar skill. I just recently learnt to use Terraform with a AZDO provider rather than the normal Azure provider and just wanted to share that.

    1. Martin Ehrnst

      I forgot to include TF and Az CLI to the post. The reason for using the native api is that we don’t use terraform for anything else 🙂 however, if you already use TF there’s no reason you shouldn’t do azdo with it

Engage by commenting