Skip to content

Fun with Office 365 Licensing

As with all Microsoft licensing options, it seems you have to have a degree to be able to understand and later assign licenses. This also goes for Office 365 licensing through Azure AD, which wasn’t easy with the MSOL module – but still isn’t exactly a walk in the park with the AzureAD module.

The new way to add or remove licenses using AzureAD Powershell is done through Set-AzureADUserLicense. First thing I usually do is look up the Microsoft Docs article on a CMDlet, which in this case did not help at all.

As usual, I under a bit of time pressure to fix some licensing issues, and all of a sudden I had to rethink the way licenses can be added or removed. I ended up creating three quick Powershell functions for this specific task.

Finding users that have a license

As mentioned, this was done on-the-clock. The function will need to be updated with proper error handling and other stuff. So the primary function for this function was to find users that actually have a specific license assigned, based on the SKU ID.

Finding the SKU ID can be done by connecting to the AzureAD module:


After this, retrieve the available SKU’s:

Get-AzureADSubscribedSku | Select SkuPartNumber,SkuID

Now, finding the SKU you need in this list is a bit of a puzzle in itself. The names speak somewhat for themselves, but you can double-check for example by checking the number of licenses available and matching that to the listing in the Azure Portal. Select the SKU you need, and store it in a variable for easy reference (in my case an ATP_ENTERPRISE SKU):

$skuid = "4ef96642-f096-40de-a3e9-d83fb2f90211"

Now the fun begins. I needed to know which users have the license attached to their account, to prevent having to update the licenses on all users. This is where my neat little function kicks in:

function listAzureLicense ($skuid) {
   $LicensedUsers = New-Object System.Collections.Generic.List[System.Object]

   # Retrieve all users from AzureAD
   $users = Get-AzureADUser -All:$true

   foreach ($user in $users) {
      if ($user.AssignedLicenses) {
      foreach ($assignedlicense in $user.AssignedLicenses) {
         if ($assignedlicense.SkuID -eq $skuid) {
   Write-Output $LicensedUsers

The function only accepts a SKU-ID as input. It will parse through all users in Azure AD, checks the assigned licenses, and finds licenses that match the input SKU ID; This might not be the most efficient way to do this, but it works. I can always come back and clean it up later.

To create a list of all users that had the ATP_ENTERPRISE license connected I used the following line:

$ATPusers = listAzurelicense -skuid $skuid

That is phase one complete. The variable will hold Azure AD user objects that have the license attached.

Removing licenses for a set of users

Removing licenses is always tricky; we are targeting actual users, so tread carefully. This is where function two comes in:

function removeAzureLicense {
   param ([string[]]$Users, [string]$skuid)

   foreach ($User In $Users) {

      try {
         $Userobj = Get-AzureADUser -SearchString $user
         if ($userobj) {
         # Create the objects we'll need to add and remove licenses
         $license = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
         $licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses

         $license.SkuId = $skuid
         $Licenses.RemoveLicenses = $skuid

         Set-AzureADUserLicense -ObjectId $userobj.objectid -AssignedLicenses $licenses
         Write-Verbose ("Removing SKU " + $skuid + " from account " + $user)

      catch {
         Write-Debug ("User " + $user + " not found")

Now, some of you paying attention might have spotted that I re-used the code in the example on the Microsoft Docs site. There is absolutely nothing wrong with taking code from examples or other folks – but make sure you know what it does.

Lets run through the script section by section. First, the input area. The script accepts either a single or array of users, and a SKU ID. After this, it iterates through the usernames, and creates the license objects mentioned in the example from Microsoft.

The license object is filled with the SKU ID of the license that needs to be removed, and then applied user through Set-AzureADUserLicense. This CMDlet is not properly named though in my opinion. The Set-AzureADUserLicense accepts either the RemoveLicenses option or the AddLicenses. There is no “set” licenses in which you can replace licenses in one go.

Using the function I removed the licenses from all folks by using the following command line:

removeAzureLicense -Users $ATPUsers.UserPrincipalName -skuid $skuid

Adding licenses to a set of users

In this particular example I was done after removing the licenses; new licenses were assigned by Azure AD Group Based Licensing which is available under Azure AD Premium P1. I figured however I would probably have to add licenses at some point, and decided to create a simple function that can do the reverse as well:

function addAzureLicense {
   param ([string[]]$Users, [string]$skuid)

   # The function accepts multiple users, parse through them
   foreach ($user in $users) {

      $userobj = Get-AzureADUser -SearchString $user

      if ($userobj) {

         $license = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
         $licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses

         $license.SkuId = $skuid
         $licenses.AddLicenses = $license
Write-Verbose ("Adding license with SKU " + $skuid + " to user " + $User)
         Set-AzureADUserLicense -ObjectId $userobj.ObjectID -AssignedLicenses $licenses
      else {
         Write-Error ("User " + $user + " not found.")

Wrapping it up..

Now, these functions are far from perfect and could use a serious polish, but they got the job done. There are some caveats however; if you try to remove a license that is the underlying requirement for another license the script will throw an error.

Also, the script does not check how much licenses are available when assigning them.

All functions are also hosted for your downloading leisure on Github! That being said, if you think can use them – please do, and drop me a line if you have any questions.

Published inAzureOffice 365Powershell

Be First to Comment

Leave a Reply

Your email address will not be published.