A Quick Refresher for Group-Based Licensing

In February 2017, Paul Cunningham reviewed group-based licensing. Apart from renaming Azure AD to Entra ID, making cosmetic updates to the admin center GUI, and refreshing the documentation, not much has changed in the way the solution works.

In 2021, Microsoft said that they would remove the requirement for Entra ID Premium P1 licenses following the transition to a new license management platform and support nested groups. The transition to the new platform has happened and no trace of the requirement is in the documentation, so that’s a welcome development that might make group-based licensing a more attractive option for tenants.

Group-based licensing is a simple and effective method to assign licenses. In a nutshell, it works as follows:

  • Licenses and their options (service plans) are associated with a security group.
  • As users join the group, Entra ID assigns the associated licenses to their account. If a user leaves the group, Entra ID removes the license.
  • The scheme works as long as licenses are available for assignment. If a license isn’t available, Entra ID can’t assign a license until the tenant either buys more licenses or removes a license from another account.
  • The only other problem is conflicting service plans. This occurs when Entra ID attempts to assign a license that includes a service plan that’s already available to the account via another license. The problem was most often seen with Exchange Online because many products include an Exchange Online Plan 1 or Plan 2 service plan. The advent of license stacking for Exchange Online in early 2023 removed this problem.

For the purpose of this discussion, I created a security group called Microsoft Fabric License Assignment Group and associated it with licenses for Microsoft Fabric and Power Automate (Figure 1). Members added to the group receive these licenses and the service plans enabled by the licenses.

License assignments via group membership

Group-based licensing
Figure 1: License assignments via group membership

Group-Based License Management

This article covers the basics of license management for Entra ID accounts using the Microsoft Graph PowerShell SDK. The assignments described in the text are direct, meaning that administrators or scripts run the Set-MgUserLicense cmdlet to add or remove licenses or service plans for user accounts.

With group-based licensing in use, direct assignments are not used. Instead, you add an account to the group used to control license assignments. For example, these commands find the identifiers for the target group and the user account to add and run the New-MgGroupMember cmdlet to add the member to the group. They’re examples of the kind of processing that you might do after adding a new account.

$GroupId = (Get-MgGroup -Filter "displayName eq 'Microsoft Fabric License Assignment Group'").Id
$UserId = (Get-MgUser -UserId Michelle.Dubois@office365itpros.com).Id
New-MgGroupMember -GroupId $GroupId -DirectoryObjectId $UserId

A couple of minutes later (assuming licenses are available), the account has the licenses assigned through group membership. As you can see from Figure 2, the account has one direct assignment and two inherited from the group.

Licenses assigned to a user account via group-based licensing
Figure 2: Licenses assigned to a user account via group-based licensing

When creating new accounts, it’s important that these accounts receive licenses as soon as possible as otherwise they cannot access any services. For this reason, any interruption to normal group-based license assignments should be investigated and rectified quickly.

To remove licenses assigned through a group, remove the account from the group membership using the Remove-MgGroupMemberByRef cmdlet:

Remove-MgGroupMemberByRef -DirectoryObjectId $UserId -GroupId $GroupId

Following the removal of the account from the group membership, Entra ID removes the licenses from the account within a couple of minutes. See this article for more information about group management using the Microsoft Graph PowerShell SDK.

Reporting Group-Based Licensing

Two years ago, I discussed how to create a licensing report for a tenant with Microsoft Graph PowerShell SDK cmdlets. That version of the report only handled direct license assignments. To upgrade the report to handle group-based licensing, the script that analyzes license data checks the licenseAssignmentStates array returned by the Get-MgUser cmdlet.

When a group-based assignment exists, the array holds information about the assigning group and the product identifier. An entry in the array is present for each product license assigned through group-based licensing.

AssignedByGroup      : ebe02ef6-c696-4cdb-92d1-011a6c2a02d2
DisabledPlans        : {}
Error                : None
LastUpdatedDateTime  : 29/09/2023 20:25:31
SkuId                : f30db892-07e9-47e9-837c-80727f46fd3d
State                : Active
AdditionalProperties : {}

It’s possible for an account to have licenses assigned directly and via a group. This doesn’t interfere with the services enabled by the licenses but duplicate assignments are a waste of licenses.

To include the data in the report, the script extracts the group assignments and loops through the set to resolve the group display name and product “friendly” name (like Office 365 E3). This information is then formatted and put into a variable that is subsequently included in the report. Here’s the loop to extract the group-based licensing assignments:

[array]$GroupAssignments = $User.licenseAssignmentStates | Where-Object {$Null -ne $_.AssignedByGroup -and $_.State -eq "Active"}
[array]$GroupLicensing = $Null
# Figure out group-based licensing assignments if any exist
ForEach ($G in $GroupAssignments) {
       $GroupName = (Get-MgGroup -GroupId $G.AssignedByGroup).DisplayName
       $GroupProductName = $SkuHashTable[$G.SkuId]
       $GroupLicensing += ("{0} assigned from {1}" -f $GroupProductName, $GroupName)
$GroupLicensingAssignments = $GroupLicensing -Join ", "

Figure 3 shows how group-based licensing assignments show up in the output report.

Group-based license assignments in the tenant licensing report
Figure 3: Group-based license assignments in the tenant licensing report

As a bonus, the report tells you when it detects duplicate license assignments and highlights accounts that haven’t signed in recently. Administrators can use this information to remove duplicate licenses and consider if the licenses assigned to accounts that aren’t in active use can either be removed or replaced with a lower license. For instance, you might be able to assign an Office 365 F1 license to an account and remove its Office 365 E3 or E5 license. Finally, the report summarizes the product SKUs assigned to users within the tenant (Figure 4).

Product license assignment for a tenant
Figure 4: Product license assignment for a tenant

You can download the updated script from GitHub. If you’ve downloaded the script before, make sure that you have version 1.3 or later.

Update: The latest version of the script includes code to report license costs. See this article for more information.

Group-Based Licensing Worth Considering

Group-based licensing isn’t difficult to set up or manage. It’s definitely a method worth considering for license management if you’re confident that license availability won’t be a problem. If you haven’t tried group-based licensing yet, why not start with a relatively unimportant license and see whether this mechanism fits into your tenant management strategy. And when you’ve assigned some licenses with groups, remember to run the report to see if any duplicate assignments exist.

Microsoft Platform Migration Planning and Consolidation

Simplify migration planning, overcome migration challenges, and finish projects faster while minimizing the costs, risks and disruptions to users.

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.


  1. Ricky Leung

    Hi Tony

    Because we use the groups to manage the license, can I change and get the group assigned with one license and service plan?

    1. Avatar photo
      Tony Redmond

      Can you change the code? Certainly. It’s just PowerShell. The question is what do you want to appear in the report…

  2. Steve

    Hi Tony,

    I got an error on line 19. Try to create an index of a NULL-Array.

    Es ist nicht möglich, einen Index auf ein NULL-Array anzuwenden.
    In C:\Temp\ReportUserAssignedLicenses-MgGraph.PS1:19 Zeichen:11
    + [string]$LicenseCost = $PricingHashTable[$License]
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    Any ideas?

    1. Avatar photo
      Tony Redmond

      The license GUID pointed to in the $License variable does not exist in the $PricingHashTable. Adding cost details to the script was a recent upgrade (see https://practical365.com/report-user-license-costs/). Have a look at the CSV file containing subscription info and check the licenses assigned to the user being processed to find the problem license.

  3. Luka

    Hi Tony,

    Is it possible to mix month-to-month and yearly licenses of the same type (Microsoft 365 standard for ex)? Does entraID differentiate those, or it’s just the license type what matters. For ex. we have 10 yearly and 10 monthly licenses, and 5 teams of 6 teams with 3 members each. When we are assigning licenses to those teams, can we just assign Standard license to each team, and EntraID will take what’s needed? Or ween need to assign monthly license to one team, and yearly to another?

    1. Avatar photo
      Tony Redmond

      AFAIK, Entra ID doesn’t distinguish monthly and yearly licenses when it comes to the license assigned to accounts, so you should be able to issue licenses via direct and group-based assignments as you want. The issue arises in the subscription renewal date. Monthly licenses obviously can expire sooner…

  4. Malte

    Thank you very much for the script, it helps me a lot. I have one more suggestion: Would it be possible to include a check to see if a user really has a license or if it was just assigned to him by a group but he didn’t get it because of missing licenses? Then it would fulfill all the requirements I need

    1. Avatar photo
      Tony Redmond

      A user has a license or they don’t. There are no phantom licenses to check…

      What you could do is check for user membership in groups used to assign licenses and then against the set of assigned licenses held by the account. If the licenses differ, you know you’ve got a problem with group-based licensing.

  5. Brenkster

    Any idea what could generate this error and how I can resolve it?
    Cannot convert value “27-Dec-2023 15:41:01” to type “System.Int32”. Error: “The input string ’27-Dec-2023 15:41:01′ was not in a correct format.”

    1. Avatar photo
      Tony Redmond

      That’s an odd error because it indicates an attempt to convert a date into an integer. When in the script does this occur?

      1. Brenkster

        Cannot convert value “05-Jan-2024 12:32:49” to type “System.Int32”. Error: “Input string was not in a correct format.”
        At C:\Users\OneDrive\_PowerShell\ReportUserAssignedLicenses-MgGraph\ReportUserAssignedLicenses-MgGraph.PS1:101 char:7
        + $DaysSinceLastSignIn = ($RunDate – $LastSignInDate).Days
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : InvalidArgument: (:) [], RuntimeException
        + FullyQualifiedErrorId : InvalidCastFromStringToInteger

        I’m in the netherlands, could it be a time zone/locality thingy?

        1. Malte

          Replacing [string] with [datetime] in line 11 solved the problem for me!

          1. Avatar photo
            Tony Redmond

            Looking at this again, the string assignment

            [string]$RunDate = Get-Date -format “dd-MMM-yyyy HH:mm:ss”

            Might not work in non-English locales. Changing it to an explicit date/time would make it work. The variable is only used in report output, so it can be in whatever format you want…

  6. Martin

    In my tenant, almost everything is reported as duplicated.
    I think this is because skus assigned by a group pop up in $User.AssignedLicenses

    1. Avatar photo
      Tony Redmond

      I found some bugs that I fixed in version 1.4. Please download from GitHub and give the code a try out.

  7. Robert Lackey

    First and foremost, I’d like to express my gratitude for your continuous contributions to the community. Your work has been instrumental in aiding many individuals and organizations in managing their IT resources more effectively.
    I downloaded Version 1.3 today and wanted your thoughts regarding a challenge I encountered while utilizing your ReportUserAssignedLicenses-MgGraph.PS1 script. Specifically, I was testing the script and noticed an issue with the output data in the Microsoft365LicensesReport.CSV (and .HTML). It appears that the license value is present in the “Direct assigned licenses” column for all users (which I know is not accurate in my tenant), and I was hoping to understand whether this is the expected behavior or point me in the direction to get this resolved?

    1. Avatar photo
      Tony Redmond

      Hi Robert,

      I think I need some more information from you to fully understand what issue you’re encountering. The value in the Direct assigned licenses column in the set of licenses directly assigned (by admins) to a user account. I see the correct licenses for the users shown for my tenant. You seem to be saying that you see an incorrect value. If so, can you run the Get-MgUserLicenseDetail cmdlet for one of the affected accounts and report the output here.


      1. Robert Lackey

        PS C:\Windows\system32> get-mguserlicenseDetail -UserId “Edward#######” | ft
        Id SkuId SkuPartNumber
        — —– ————-
        hr6frJHNBUGIN57CVSj4Su7E6wa1G91HgSARMkvFTgY 06ebc4ee-1bb5-47dd-8120-11324bc54e06 SPE_E5

    2. Avatar photo
      Tony Redmond

      For instance, if you look at the Direct assigned licenses column shown in Figure 1 in the article, you see that different licenses are reported for different accounts. These values come from Get-MgLicenseDetail.

    1. Avatar photo
      Tony Redmond

      Yes, that’s the current position. But it’s also true that Microsoft made a commitment to remove the Premium P1 requirement when they migrate Entra ID to a new licensing platform. According to Alex Simons, VP for Marketing in Entra ID, that work is still progressing, but it will conclude sometime. The only question is when.

Leave a Reply