Use the Graph SDK to Manage Group-Based Licensing
Make License Assignment Easier with Group-Based Licensing and PowerShell
Group-based licensing is a mechanism by which user accounts receive product licenses through membership of a group. In September 2024, Microsoft moved the UI to control group-based licensing from the Entra admin center to the Microsoft 365 admin center. The move didn’t meet with universal approval, but that’s how things work now.
Group-based licensing works by creating a group, adding members to the group, and associating the group with one or more licenses. The group must be a security group and each group member must have an Entra P1 license. Figure 1 shows that I am using a group called Teams EEA license holders to assign the Teams-only licenses created after Microsoft split Teams out from other products like Office 365 E3 and Microsoft 365 E5.
Graph SDK Cmdlets for Group-Based Licensing
Behind the scenes, the Microsoft 365 admin center calls Graph APIs to assign and control licenses. In the case of group-based licensing, the Microsoft Graph PowerShell SDK cmdlet to use is Set-MgGroupLicense. The cmdlet works very much like the Set-MgUserLicense cmdlet, which assigns licenses directly to user accounts (here’s an example of how to switch licenses with Set-MgUserLicense).
For instance, to assign another license to the group (and therefore to the group members), run the Set-MgGroupLicense cmdlet after finding the identifier for the group to assign the licenses:
Get-MgGroup -Filter "displayName eq 'Teams EEA License Holders'" | Format-Table DisplayName, Id, Description DisplayName Id Description ----------- -- ----------- Teams EEA License Holders 90bbfa24-4413-4ffe-8e0a-2c7f10cea873 People with Teams EEA licenses Set-MgGroupLicense -GroupId 90bbfa24-4413-4ffe-8e0a-2c7f10cea873 -AddLicenses @{SkuId = '8c4ce438-32a7-4ac5-91a6-e22ae08d9c8b'} -RemoveLicenses @()
Just like direct assignments, group-based licensing supports disabling any of the service plans included in a product license.
Adding a license to a group like this is a cumulative update, and the new license joins any already assigned by the group. To confirm that this is the case, run the Get-MgGroup cmdlet and examine the AssignedLicenses property:
Get-MgGroup -GroupId 90bbfa24-4413-4ffe-8e0a-2c7f10cea873 -Property "AssignedLicenses" | Select-Object -ExpandProperty AssignedLicenses DisabledPlans SkuId ------------- ----- {} 8c4ce438-32a7-4ac5-91a6-e22ae08d9c8b {} 7e74bd05-2c47-404e-829a-ba95c66fe8e5
To remove a license from the group members, run Set-MgGroupLicense and include the SKU identifier to remove in the RemoveLicenses array:
Set-MgGroupLicense -GroupId 90bbfa24-4413-4ffe-8e0a-2c7f10cea873 -AddLicenses @{} -RemoveLicenses @('8c4ce438-32a7-4ac5-91a6-e22ae08d9c8b')
Background jobs process the actions required to assign or remove licenses from group members. Depending on the number of assignments to process, the license assignments should be complete in a matter of minutes rather than hours.
Checking License Assignments
To check license assignments, run the Get-MgUser cmdlet and check the contents of the licenseAssignmentStates property. Direct-assigned licenses don’t have a value in the AssignedByGroup property, while licenses assigned through a group have the group identifier listed. The output below shows that the user has one license assigned through a group and two assigned directly:
Get-MgUser -Userid Kim.Akers@Office365itpros.com -Property Id, displayname, assignedLicenses, licenseAssignmentstates | Select-Object -ExpandProperty licenseAssignmentstates | Where-Object {$_.Error -eq 'None' -and $_.State -eq 'Active'} | Format-Table AssignedByGroup, @{expression={$SkuHashTable[$_.SkuId]};label="Product"}, LastUpdatedDateTime AssignedByGroup Product LastUpdatedDateTime --------------- ------- ------------------- 90bbfa24-4413-4ffe-8e0a-2c7f10cea873 Microsoft Teams EEA 28/10/2024 19:41:39 Microsoft Power Automate Free 28/10/2024 19:38:38 Office 365 E5 EEA (No Teams) 28/10/2024 19:38:38
Microsoft has a page of PowerShell examples for group-based licensing. Here’s a modified version of a script to report all the groups used for licensing assignments in a tenant.
To make the output easier to understand, the code looks up the product SKU identifier for each license against a hash table built from the Get-MgSubscribedSku cmdlet. You could also build the hash table from the CSV file available from Microsoft’s product names and service plan identifiers page, which is how product identifiers are translated to names by the Microsoft 365 licensing report script. The code to create a hash table from the downloaded CSV file is available from GitHub.
[array]$Skus = Get-MgSubscribedSku $SkuHashTable = @{} ForEach ($Sku in $Skus) { $SkuHashTable.Add($Sku.SkuId, $Sku.SkuPartNumber) } [array]$Groups = Get-MgGroup -All -PageSize 500 -Filter "assignedLicenses/`$count ne 0" ` -ConsistencyLevel Eventual -CountVariable Count ` -Property LicenseProcessingState, DisplayName, Id, AssignedLicenses | ` Select-Object DisplayName, Id, AssignedLicenses -ExpandProperty LicenseProcessingState If (!($Groups)) { Write-Host "No groups used for license assignment found... exiting!"; break } $Report = [System.Collections.Generic.List[Object]]::new() ForEach ($Group in $Groups) { # Report SKU names rather than identifiers $ProductLicenseNames = [System.Collections.Generic.List[Object]]::new() ForEach ($License in $Group.AssignedLicenses) { $ProductLicenseNames.Add($SkuHashTable[$License.SkuId]) } [array]$GroupMembers = Get-MgGroupMember -GroupId $Group.Id -All -Property Id, displayName, LicenseProcessingState $ReportLine = [PSCustomObject] @{ 'Group name' = $Group.DisplayName GroupId = $Group.Id 'Assigned licenses' = $ProductLicenseNames -join ", " 'Total Users' = $GroupMembers.count 'Processing state' = $Group.State } $Report.Add($ReportLine) } $Report | Format-Table 'Group Name', 'Total Users', 'Processing state', 'Assigned Licenses' -Wrap Group name Total Users Processing state Assigned licenses ---------- ----------- ---------------- ----------------- Teams EEA License Holders 5 ProcessingComplete Microsoft Teams EEA Microsoft Fabric License Assignment Group 9 ProcessingComplete Microsoft Stream, Microsoft Power Automate Free, Microsoft Power BI (free)
As Easy as User Direct Assignments
Group-based licensing is no more difficult to master than direct license assignments. The major difference is that you’re working with a group rather than a user account. Once you get that fact straight, everything flows naturally.
Need more advice about how to write PowerShell for Microsoft 365? Get a copy of the Automating Microsoft 365 with PowerShell eBook, available standalone or as part of the Office 365 for IT Pros eBook bundle.