Table of Contents
Licensing Report Has No Dates
I recently published a Practical365.com article explaining how to create a licensing report for an Office 365 tenant using cmdlets from the Microsoft Graph SDK for PowerShell.
A reader asked: “I am trying to determine when a specific license, in this case an E3 Security and Mobility license, was added for all users.”
No Dates for Licenses
It’s an interesting question. As written, my script generates a report based on the licenses and service plans assigned to user accounts. However, it doesn’t do anything to tell you when a license for a product like Enterprise Security and Mobility E3 (EMS E3) is assigned to a user. This is because Azure AD does not record assignment dates for the product license information held for user accounts. Instead, license information for an account is presented as a table of SKU identifiers with any disabled service plans in a SKU noted:
$User,AssignedLicenses DisabledPlans SkuId ------------- ----- {bea4c11e-220a-4e6d-8eb8-8ea15d019f90} b05e124f-c7cc-45a0-a6aa-8cf78c946968 {} 8c4ce438-32a7-4ac5-91a6-e22ae08d9c8b {} 4016f256-b063-4864-816e-d818aad600c9 {a23b959c-7ce8-4e57-9140-b90eb88a9e97} 6fd2c87f-b296-42f0-b197-1e91e994b900
However, date information is included in the service plan information for an account:
$User.AssignedPlans AssignedDateTime CapabilityStatus Service ServicePlanId ---------------- ---------------- ------- ------------- 09/11/2021 10:33:37 Enabled AzureAdvancedThreatAnalytics 14ab5db5-e6c4-4b20-b4bc-13e36fd2227f 09/11/2021 10:33:37 Enabled AADPremiumService eec0eb4f-6444-4f95-aba0-50c24d67f998 09/11/2021 10:33:37 Enabled RMSOnline 5689bec4-755d-4753-8b61-40975025187c 09/11/2021 10:33:37 Enabled SCO c1ec4a95-1f05-45b3-a911-aa3fa01094f5 09/11/2021 10:33:37 Enabled AADPremiumService 41781fb2-bc02-4b7c-bd55-b576c07bb09d 09/11/2021 10:33:37 Enabled MultiFactorService 8a256a2b-b617-496d-b51b-e76466e88db0 09/11/2021 10:33:37 Enabled RMSOnline bea4c11e-220a-4e6d-8eb8-8ea15d019f90 09/11/2021 10:33:37 Enabled RMSOnline 6c57d4b6-3b23-47a5-9bc9-69f17b4947b3 09/11/2021 10:33:37 Enabled Adallom 2e2ddb96-6af9-4b1d-a3f0-d6ecfd22edb2
Checking Dates for Service Plan Assignments
Given that date information is available for service plans, it should therefore be possible to check against the service plan information for user accounts to find assignments of a service plan belonging to a product (SKU). Looking at the Product names and service plan identifiers for licensing page , we find the list of service plans included in EMS E3 (SKU identifier efccb6f7-5641-4e0e-bd10-b4976e1bf68e). The set of service plans are:
- Azure Active Directory Premium P1: 41781fb2-bc02-4b7c-bd55-b576c07bb09d
- Azure Information Protection Premium P1: 6c57d4b6-3b23-47a5-9bc9-69f17b4947b3
- Cloud App Security Discovery: 932ad362-64a8-4783-9106-97849a1a30b9
- Exchange Foundation: 113feb6c-3fe4-4440-bddc-54d774bf0318
- Microsoft Azure Active Directory Rights: bea4c11e-220a-4e6d-8eb8-8ea15d019f90
- Microsoft Azure Multi-Factor Authentication: 8a256a2b-b617-496d-b51b-e76466e88db0
- Microsoft Intune: c1ec4a95-1f05-45b3-a911-aa3fa01094f5
The theory is that you should be able to check accounts assigned EMS E3 to retrieve information about one of the service plans in the SKU and retrieve and report the assigned date. I don’t have EMS E3 in my tenant, but I do have EMS E5. I therefore checked the theory by running this PowerShell code:
# Check the date when a service plan belonging to a product like EMS E3 is assigned to an account $EMSE3 = "efccb6f7-5641-4e0e-bd10-b4976e1bf68e" # Product SKU identifier for Enterprise Mobility and Security E3 $EMSE5 = "b05e124f-c7cc-45a0-a6aa-8cf78c946968" # Product SKU identifier for Enterprise Mobility and Security E5 $TestSP = "41781fb2-bc02-4b7c-bd55-b576c07bb09d" # Azure Active Directory Premium P1 $Report = [System.Collections.Generic.List[Object]]::new() # Find tenant accounts Write-Host "Finding Azure AD accounts..." [Array]$Users = Get-MgUser -Filter "UserType eq 'Member'" -All | Sort DisplayName ForEach ($User in $Users) { ForEach ($SP in $User.AssignedPlans) { If (($User.AssignedLicenses.SkuId -contains $EMSE5) -and ($SP.ServicePlanId -eq $TestSP -and $SP.CapabilityStatus -eq "Enabled")) { $ReportLine = [PSCustomObject][Ordered]@{ User = $User.DisplayName UPN = $User.UserPrincipalName ServicePlan = $SP.Service ServicePlanId = $SP.ServicePlanId Assigned = Get-Date($SP.AssignedDateTime) -format g } $Report.Add($ReportLine) } #End if } #End ForEach Service plans } #End ForEach Users
After defining some variables, the code calls the Get-MgUser cmdlet to find the Azure AD accounts in the tenant (I used the script described in this article as the basis; see this article for more information about the Microsoft Graph SDK for PowerShell). Make sure that you connect to the beta endpoint as license information is not available with the V1.0 endpoint (run Select-MgProfile beta after connecting to the Graph).
Next, the code checks the assigned plans and if the desired plan belongs to the right product and is enabled, we report it. Each line in the report is like this:
User : Kim Akers UPN : Kim.Akers@office365itpros.com ServicePlan : AADPremiumService ServicePlanId : 41781fb2-bc02-4b7c-bd55-b576c07bb09d Assigned : 11/11/2017 16:52
This is a quick and dirty answer to the problem of discovering when a product license is assigned to user accounts. It might serve to fill in while Microsoft improves matters.
As reported by Vasil Michev, Microsoft recently added a licenseAssignmentState resource to the Graph API. This isn’t yet available for PowerShell, but the date information can be retrieved using the Graph. In this snippet, we find user accounts and examine their assignment state for EMS E5 to discover when the license was assigned. The code assumes that you’ve already used a registered app to authenticate and fetch an access token to interact the Graph APIs. Remember that you might need to use pagination to fetch all the pages of user data available in the tenant. Anyway, here’s my quick and dirty code to prove the point:
# Use the Graph API to check license assignment states Write-Host "Fetching user information from Azure AD..." $Uri = "https://graph.microsoft.com/v1.0/users?&`$filter=userType eq 'Member'" [Array]$Users = (Invoke-RestMethod -Uri $Uri -Headers $Headers -Method Get -ContentType "application/json") $Users = $Users.Value Write-Host “Processing users…” ForEach ($User in $Users) { $Uri = "https://graph.microsoft.com/beta/users/" + $User.UserPrincipalName + "?`$select=licenseAssignmentStates" [Array]$Assignments = Get-GraphData -Uri $Uri -AccessToken $Token ForEach ($License in $Assignments.LicenseAssignmentStates) { $LicenseUpdateDate = $Null If ($License.SkuId -eq $EMSE5 -and $License.State -eq "Active") { If ([string]::IsNullOrWhiteSpace(($License.lastUpdatedDateTime)) -eq $False ) { $LicenseUpdateDate = Get-Date($License.lastUpdatedDateTime) -format g } Else { $LicenseUpdateDate = "Not set" } Write-Host ("Last update for EMS for {0} on {1}" -f $User.DisplayName, $LicenseUpdateDate) } } # End ForEach License } # End ForEach User Last update for EMS for Tony Redmond on 15/07/2021 15:28 Last update for EMS for Andy Ruth (Director) on Not set Last update for EMS for Kim Akers on 26/10/2021 16:58 Last update for EMS for Jack Hones on Not set Last update for EMS for Oisin Johnston on 03/10/2020 13:18
The dates retrieved using this method differ to the values you get from service plans because Microsoft is populating these values using the last licensing change made to the account. However, in the future, the dates will be more accurate and usable because they will capture changes, hopefully when PowerShell access is possible.
No Audit Data
In passing, I note that the Office 365 audit log captures a “Change user license” audit record when an administrator updates the licenses for an account. However, the audit record doesn’t include details of what licenses were added, changed, or removed. The Azure AD team could do a better job of capturing audit information about license updates. I’m sure they’ll be happy to hear that.
Keep up with the changing world of the Microsoft 365 ecosystem by subscribing to the Office 365 for IT Pros eBook. Monthly updates mean that our subscribers learn about new development as they happen.
I was experimenting with this today, but when I do the get-mguser query, the assignedplans is always blank. Any idea what would cause this?
You’re probably using the V1.0 endpoint. Make sure that you select the Beta endpoint as that’s when the license information is exposed.
Yep, that was it. Thanks again.