Migrating to Group Based Licensing – Removing statically assigned Licenses

By | July 17, 2020

So let say we have a situation. Our Office tenant has been running for 5 years and gathered some 60000 users all have their licenses assigned directly.

Some by On-boarding scripts, some by joiner processes, some by service request, some seemingly by random dice rolls or monkeys whose time would be better spent typing out Merchant of Venice.

Microsoft have a lovely guid on how to do this1, however it stops at part 5 and offers the advice

“Consider removing the original direct assignments. We recommend that you do it gradually, and monitor the outcome on a subset of users first. If you could leave the original direct assignments on users, but when the users leave their licensed groups they retain the directly assigned licenses, which might not be what you want.”

Yeah, using group based licensing but not having membership of a group control the licensing pretty much exactly “might not be what you want”. So anyway. Where Microsoft’s guidance has left you is with this:
(I’ve obviously blanked out the SKUId prefix and GUIDS)

PS C:\Users\matt> get-msoluser -UserPrincipalName testuser@domain.com | select -expandproperty licenses | select AccountSkuID,GroupsAssigningLicense

AccountSkuId                        GroupsAssigningLicense                                                      
------------                        ----------------------                                                      
domain:EMS                     {<<GroupSKU>>, <<UserObjectID>>}
domain:PROJECTPROFESSIONAL     {<<UserObjectID>>}                                      
domain:Win10_VDA_E3            {<<GroupSKU>>, <<UserObjectID>>}
domain:VISIOCLIENT             {<<UserObjectID>>}                                      
domain:DYN365_ENTERPRISE_SALES {<<UserObjectID>>}                                      
domain:FLOW_FREE               {<<UserObjectID>>}                                      
domain:ENTERPRISEPACK          {<<GroupSKU>>, <<UserObjectID>>}

So what we see is we have assigned some 365 licenses, (office, win10 and EMS) with groups while the optional licenses like Visio we left direct assigned. We are moving from direct licensing to group so the original direct licensing assignment is still present – it’s represented by the User Object ID. This means if we remove the user from the group they will still have the license, which is balls.

NOTE: The things ONLY direct assigned will sometimes have nothing in the GroupsAssigningLicense field which makes the script a little more annoying)

Okay first thing we need is to output all of our license assignment in case we need to revert anything:
(You can edit $Users = to target a more specific set)

# Connect-MSOLService

$Users = Get-MsolUser -all

$OutputFile1 = ".\AllLicensesAndMethod"+(Get-date -Format _HHmm_ddMMyyyy)+".csv"
$content = "User,License,AssignedBy"
Add-Content -path $OutputFile1 $content

$i = 0
ForEach ($User in $Users) {
    $i++
    Write-Host "Processing" $i "of" $Users.Count "-" $User.UserPrincipalName -ForegroundColor Cyan
    $UserLicenses = Get-MSOLUSer -UserPrincipalName $User.UserPrincipalName | select -ExpandProperty Licenses
    ForEach ($license in $UserLicenses) {
        $ThisLicenseSKU = $license.AccountSku.SkuPartNumber
        $ThisLicenseGroups = $license.GroupsAssigningLicense
        If (!$ThisLicenseGroups) {
            Write-Host $ThisLicenseSKU "- Static Assignment blonk"
            $content=$user.UserPrincipalName+","+$ThisLicenseSku+",StaticAssignment"
        }
        ForEach($GroupID in $ThisLicenseGroups) {
            If ($GroupID.Guid.ToString() -eq $User.ObjectId.ToString()) {
                Write-Host $ThisLicenseSKU "- Static Assignment nomatch"
                $content=$user.UserPrincipalName+","+$ThisLicenseSku+",StaticAssignment"
            }
            If ($GroupID.GUID -ne $User.ObjectId) {
                $group = Get-MsolGroup -ObjectId $GroupID.GUID.ToString()
                Write-Host $ThisLicenseSKU $group.DisplayName
                $content=$user.UserPrincipalName+","+$ThisLicenseSku+","+$group.DisplayName
            }
            Add-Content -path $OutputFile1 $content
        }
    }   
}

This spits out every license assignment on a new line along with “static assignment” if its a static assignment or the group name if it’s assigned by group”

This basically just tells us where Microsoft left us off. Next we need to identify every license that is assigned statically and by group then remove the static assignment

# Connect-MSOLService

$Users = Get-MsolUser -all
$i = 0
ForEach ($User in $Users) {
    $i++
    Write-Host "Processing" $i "of" $Users.Count "-" $User.UserPrincipalName -ForegroundColor Cyan

    $UserLicenses = Get-MSOLUSer -UserPrincipalName $User.UserPrincipalName | select -ExpandProperty Licenses

    ForEach ($license in $UserLicenses) {    
    $Direct="False"
    $Group="False"
        $ThisLicenseSKU = $license.AccountSku.SkuPartNumber
        $ThisLicenseSKUID = $license.AccountSkuId
        $ThisLicenseGroups = $license.GroupsAssigningLicense
        If ($ThisLicenseGroups.Count -gt 1) {
            ForEach($GroupID in $ThisLicenseGroups) {
                If ($GroupID.Guid.ToString() -eq $User.ObjectId.ToString()) {
                    Write-Host $ThisLicenseSKU "- Static Assignment"
                    $Direct="True"
                    If ($Group -eq "True") {
                        Write-Host "This license assigned by group and static - i will remove static" $ThisLicenseSKUID -ForegroundColor Yellow 
                        Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -RemoveLicenses $ThisLicenseSKUID
                    }
                }
                If ($GroupID.GUID -ne $User.ObjectId) {
                    $group = Get-MsolGroup -ObjectId $GroupID.GUID.ToString()
                    Write-Host $ThisLicenseSKU $group.DisplayName
                    $Group="true"
                    If ($Direct -eq "True") {
                        Write-Host "This license assigned by group and static - i will remove static" $ThisLicenseSKUID -ForegroundColor Red
                        Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -RemoveLicenses $ThisLicenseSKUID
                    } 
                }
            }
        }
    }   
}

You can then rerun the first script to confirm that you have no static assignments for licenses that are applied by group (Overlapping groups wont be affected – they will stack) and that statically assigned licenses (Visio, etc in the example) are unaffected.

The big Gotcha here is customisation – If you customise the activated and deactivated parts of your group licenses – i.e. have a group that applies and E3 license but not the OneDrive entitlement then use a static assignment to turn on the OneDrive entitlement for a subset of user that will be stripped! The solution is to apply both by overlapping group but be aware!

Links

1 – Microsoft – How to migrate users with individual licenses to groups for licensing https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/licensing-groups-migrate-users

Loading

3 thoughts on “Migrating to Group Based Licensing – Removing statically assigned Licenses

  1. Doug Brewer

    Hi Matt
    I have searched the web over and over and finally found your page.
    I was looking for a script that would export users and their Direct & Group Assigned Licenses like it does in Azure and yours does pretty much what I am needing. Thank you so much!

    I do have a question as I am still learning PS.
    Is there anyway to combine the AssignedBy field output to show StaticAssignment and GroupAssignedName for each License assigned?

    Example:
    User,License,AssignedBy
    User1@contoso.com, SPE_F1, StaticAssignment,O365_F3
    User1@contoso.com, ATP_Enterprise,StaticAssignment
    Groupname would be the group assigning the license?

    Thank you again for the great script. Will save a lot of time!

    Reply
    1. jmattmacd Post author

      Sorry I’m not sure I follow. The first script will output every license assignment on a new line – so if you have users with EMS assigned by group and also assigned manually (or by multiple groups) you will get a line for each assignment, do you want a line for each license and all the ways it gets assigned instead?

      This should do that, the assignment methods are separated by “;” or your csv will be a mess, its easy enough to change though:

      # Connect-MSOLService

      $Users = Get-MsolUser -All
      $OutputFile1 = ".\AllLicensesAndMethod"+(Get-date -Format _HHmm_ddMMyyyy)+".csv"
      $content = "User,License,AssignedBy"
      Add-Content -path $OutputFile1 $content

      $i = 0
      ForEach ($User in $Users) {
      $i++
      Write-Host "Processing" $i "of" $Users.Count "-" $User.UserPrincipalName -ForegroundColor Cyan
      $UserLicenses = Get-MSOLUSer -UserPrincipalName $User.UserPrincipalName | select -ExpandProperty Licenses
      ForEach ($license in $UserLicenses) {
      $Assignedby = $null
      $ThisLicenseSKU = $license.AccountSku.SkuPartNumber
      $ThisLicenseGroups = $license.GroupsAssigningLicense
      If (!$ThisLicenseGroups) {
      Write-Host $ThisLicenseSKU "- Static Assignment blonk"
      #$content=$user.UserPrincipalName+","+$ThisLicenseSku+",StaticAssignment"
      If ($Assignedby) {
      $Assignedby = $AssignedBy + ";StaticAssignment"
      }
      If (!$Assignedby) {
      $Assignedby = "StaticAssignment"
      }
      }
      ForEach($GroupID in $ThisLicenseGroups) {
      If ($GroupID.Guid.ToString() -eq $User.ObjectId.ToString()) {
      Write-Host $ThisLicenseSKU "- Static Assignment nomatch"
      #$content=$user.UserPrincipalName+","+$ThisLicenseSku+",StaticAssignment"
      If ($Assignedby) {
      $Assignedby = $AssignedBy + ";StaticAssignment"
      }
      If (!$Assignedby) {
      $Assignedby = "StaticAssignment"
      }
      }
      If ($GroupID.GUID -ne $User.ObjectId) {
      $group = Get-MsolGroup -ObjectId $GroupID.GUID.ToString()
      Write-Host $ThisLicenseSKU $group.DisplayName
      #$content=$user.UserPrincipalName+","+$ThisLicenseSku+","+$group.DisplayName
      If ($Assignedby) {
      $Assignedby = $AssignedBy + ";"+$group.DisplayName
      }
      If (!$Assignedby) {
      $Assignedby = $group.DisplayName
      }
      }
      }
      $content = $user.UserPrincipalName+","+$ThisLicenseSku+","+$AssignedBy
      Add-Content -path $OutputFile1 $content
      }
      }

      Reply
  2. Doug Brewer

    Thanks Matt!
    This will greatly help with migrating users over to the group licensing. I got users that have both group and direct assigned. I am trying to clean it up. Again thank you!

    Reply

Leave a Reply

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