Menu Close

Manage Azure DevOps user licenses with PowerShell

In Azure DevOps, choosing User licenses is relatively pain free. There are a few flavors, some are free, some are not. While the portal works alright for small tasks, the Azure DevOps Rest API is very useful in automating license management. In this blog post, I want to show you how you can list and manage Azure DevOps user licenses with PowerShell and the Rest API.

About Azure DevOps Licenses

Manage Azure DevOps user licenses with PowerShell

Azure DevOps user licenses have the following options:

Stakeholders

This license is free to use. The options are limited though. With the biggest restriction in my experience that you are not able to read code. But there are smaller limitations. You can for example read the boards, but you are not able to drag the work items to a different place on the board.

Basic and Basic + Test Plans.

These licenses give you full options to use Azure DevOps, with the only difference between the two that the lather can create and manage test plans.
You get 5 basic licenses for free.

Visual studio Enterprise

If a user has Visual studio Enterprise licenses or benefits, they can possible make use of that for Azure DevOps. Read about it here.

Open Source

This is for projects rather than users, but it is worth mentioning that a project that is publicly available does not have limitations based on licenses, everything is free (within a limit of projects)

Visual studio enterprise level

To get full details on all the licensing possibilities, go to https://azure.microsoft.com/en-us/pricing/details/devops/azure-devops-services/?WT.mc_id=DOP-MVP-5003674

Managing User Licenses

Let’s consider our options to manage user licenses besides PowerShell and the Rest API.

Manage user licenses in the portal

The portal for users in Azure DevOps is pretty straight forward. It works well for small changes. The only thing you need to do is go to the organization settings and then the User interface. By clicking the three dots and “Change Access level”, you can change the license. For single operations, this can be the way to go. But as your organization grows, you will want to implement automation. Find out here how to manage the licenses in the portal.

Manage Azure DevOps user licenses with PowerShell

Manage user licenses with Group rules

It is possible to assign users licenses and permissions through Group Rules. I encourage you to see if this would fit your needs for simplicity. For more flexibility you can move to the Rest API. Click here to find out more about group rules

Manage user licenses with the Azure DevOps CLI

The Azure CLI supports a lot of options in Azure DevOps. If your use case provides an option to install the CLI (or use cloud shell), this can be a nice option for automation.   You can find more information about it here.

Using PowerShell to manage user licensing

By using the Azure DevOps Rest API, you can interact with the licenses that users have been assigned. You could get a list of all user licenses, change licenses based on login time or allow new AzureAD users access if they are not connected yet.   For full references on the API, see the Microsoft Docs.

VsTeam PowerShell Module

Want to work more with the API with PowerShell without delving into the Rest API? Donovan Brown has created the module VSTeam as a nice wrapper. You can download it from the Gallery. I have chosen to connect directly to the API here because I want to show how it works.

Prerequisites

To connect to the API, you need a PAT token with the correct permissions. Find out how to create one here.
The users account that provides the PAT token needs to be a member of the Project Administrators group or Project Collection Administrators group.
If you plan to automatically run the code, for example from a Function App, you should use a service account with this permission.

Create a header for the API

So if you want to connect to the API, you first create a header with that PATkey. Then you can use the header to get or change data in Azure DevOps. You can create the header like this:

With this header, you can call the API by using it in the cmdlet Invoke-RestMethod.

To show the possibilities, I will show some examples of things you can do

Get all users licenses status

The following snippet gets you all the users in your Azure DevOps organization and their license status.

Note: This call will only show the first page of users, which are about a 100 users. If your organization has more users, you will want to add ?top=1000 or something like that to the URL. Thank you Bryan in the comments for pointing that out!

Change a license

To change license, you need to use the POST method. You can use this code to change the license for an existing user.

Use case: Change license based on last login date

An example from the field. I helped a company that had a lot of users, but some of them only used Azure DevOps temporary, for example for the management of a project. Often they forgot to report they didn’t need the license any more.

I created a scheduled Azure Function app for them that would check all users that were using a basic license. If they had last logged in more than a month ago, their license was scaled down to stakeholder. This way people who weren’t actively using their account would not cost money. Licenses can be assigned instantly, so if someone did need it the action could be reversed in no time.

Note: if you assign a license, you pay for it directly. If you remove a license, your bill will be lower the next month. So this strategy only works when you deal with users not logging in for a longer time.

This is the script that I created for this use case (this is a modified version, the actual version was used in a Function App)

Conclusion

So with this post I wanted to show you the options to manage Azure DevOps user licenses with PowerShell and the Rest API. I hope these examples can help you get started. If it does, don’t hesitate to look at all the other options available with the API, or take a look at the PowerShell module VSTeam to have a more readable solution.

19 Comments

  1. bryan marks

    Do these still work for you…I get errors on both the change license where it can’t find the email address and the remove license where it just throws an error

    operationResults
    —————-
    {@{isSuccess=True; errors=System.Object[]; userId=removedguid; …

    • Barbara

      Hi Bryan,
      I just checked the functions in the script and they work for me.
      Did you make sure to change this line?
      $Emailaddress = "User@domain.com"

      The first error suggests that the user cannot be found.

      The line with operation Results is actually expected behavior and the isSuccess-value seems to be true, so you could check if it actually did make the change in your organization.

      • Bryan

        Ok this is really strange, and I think see what’s going on now…when I run an output of all of my users I only get my users A-D…and those are the email addresses I can find..did you run into anything like this

        #Splat the parameters in a hashtable for readability
        $UsersParameters = @{
        Method = “GET”
        Headers = $Header
        Uri = “https://vsaex.dev.azure.com/$OrganizationName/_apis/userentitlements?api-version=5.1-preview.2”
        }
        # Collect all the users
        $Users = (Invoke-RestMethod @UsersParameters).members

        # Create a readable output
        $Output = [System.Collections.ArrayList]@()
        $Users | ForEach-Object {
        $UserObject = [PSCustomObject]@{
        UserName = $_.user.principalName
        License = $_.accessLevel.licenseDisplayName
        }
        [void]$Output.Add($UserObject)
        }

        #Return the outputArray
        $Output

        Only outputs about 100 users starting at

        Abdeen.wahab…
        ending at
        Derek.luenig and doesn’t output anyone beyond that

  2. Bryan

    Hey Barbara,
    I thought I’d share this with you…working with Microsoft I discovered why I kept getting Email address not found for some users. The API URL by default only shows 1 page of users, to specify more you need to call it in the URL which looks something like

    “https://vsaex.dev.azure.com/$OrganizationName/_apis/userentitlements?top=1000&api-version=5.1-preview.2”

    Thank you for writing this blog, it’s solving a lot of problems for me once I get around the Microsoft limitations I should be set to run automation and remove users.

    • Barbara

      Hey Bryan,
      Great find! I have indeed only tested the scripts in small organizations. I have added a note to the post.
      Thank you for taking the time to show you solution.

      Barbara

    • Barbara

      Hi Fred,
      I have stored the code in GitHub Gists. At the bottom of each code block, you can find the text hosted with ❤ by GitHub. If you click the filename before that text, you can find the Gist with the code and give it a Star is to keep track if you want to.

  3. Chris

    Does removing a user’s entitlement also remove their Visual Studio licensing? This is something my company is looking to automate via REST API.

    • Barbara

      Hi Chris,
      This only works with basic and stakeholder licences. If someone has visual studio enterprise benefits on their (AzureAD) account, these will be applied automatically in Azure DevOps. The license is assigned outside of Azure DevOps, so it cannot be managed with the API in this post.

    • Barbara

      Hi Nicolas,

      You could collect all the users that need to be changed through an API call or by calling a file, for example a csv.
      Then you can use a foreach-loop to then walk through all these users and change them one by one. So the logic would be on the PowerShell side of things.

  4. Pingback:azure devops remove direct assignments - bestdatatoday

  5. Neelima Bajpai

    Hello Team,

    To perform the Get all users licenses status, is there video available to perform the steps one by one and similarly for changing the license from Basic to stockholder.

Leave a Reply

Your email address will not be published. Required fields are marked *