M365 Licensing With Graph PowerShell Module Part 1
You can ask just about anyone. Microsoft’s myriad licenses and licensing models for their myriad products is a quizzical quagmire that conquers most quixotic questers that challenge its mystery. There are consultancies who make significant income sending their MS licensing experts to clients to help sort out that knot. My look is going to be focused on the fairly standard M365 licenses and some situations one can get into.
Table Of Contents
Woodward and Bernstein would read this section
It’s the slog. It’s the boring part. There’s no code here. This is some background. Microsoft has a number of plans that can be right for your business. Seriously, though, make sure to talk to your account reps. In smaller orgs, or organizations with fairly flat and standardized types of people, this usually isn’t too difficult. I don’t work in an organization like that. We’ve got hundreds of thousands of users that all occupy various niches of status.
And how does that make you feel
We have a mix of E1 and E5, and something like 95 groups that have licenses assigned to them using the new and “easier” group-based licensing. I say “new” because I’ve been in this space since before it was standardized and, in using the logic that was already extant to manage all of these users on-prem, it was actually a little easier to deal with back then.
License conflicts can be show stoppers and licenses may not be applied at all, at times. Yes, this type of work lived in my wheelhouse. No, I don’t want to elaborate. Suffice it to say that this work is being democratized with further participation of our latest IdP but the licensing component is not in place. We get licensing tickets regularly and I’d… prefer not to. So let’s take a deep dive.
Where in the world is (all this license information)
Alright, gumshoe, we need to start by seeing. By gathering information. By compiling. By correlating. It’s a process. But that’s good, because people like process. We can add some snappy cuts and use environmental storytelling to tell a compelling story of your journey through my journey. We won’t. We won’t even film it. But we could. Anyway, there’s some ground work to lay down.
Connect-MGGraph is our friend
We need to Connect-MGGraph and, what we’re looking for here specifically are the permissions User.Read.All
, LicenseAssignment.Read.All
, and Group.Read.All
. These permissions, surprising no one, will allow us to read all information about users, license assignments, and groups. And we’ll use each one. Altogether it will look like this:
# The standard look
Connect-MgGraph -Scopes "User.Read.All", "LicenseAssignment.Read.All", "Group.Read.All"
# Sometimes I like to use UseDeviceAuthentication because it's a process for me to log in
Connect-MgGraph -Scopes "User.Read.All", "LicenseAssignment.Read.All", "Group.Read.All" -UseDeviceAuthentication
You can also check the official documentation to see the various ways that you can connect. The important part is that you, or your app, or your managed identity, have those permissions. If you run into issues, you may need to be specifying your tenant.
With trembling hands I made a tiny command
You’d think that using the very obvious command of Get-MgUser
would give us what we’re looking for. You would think that because there is a field in the returned object AssignedLicenses
and, in my case, it’s wonderfully blank. Lovely. But where there is a will, there is a way. So we dig deeper and don’t let the filled-in passages deter us. Like Howard Carter we keep going and we find that Get-MgUserLicenseDetail
exists. So, uncovering that documentation and it looks like it’s going to do what we need.
You’ll note from the docs page that we can use our lovely Entra User ID to get the details for the licenses assigned to a user. And what we get for our trouble is another two IDs: an Id
, that is not particularly helpful for our purposes but represents this specific assignment, and a SkuId
which is much more helpful. But it’s also another lookup. Fun stuff. If we’re trying to report on a large number of users, we would probably want to keep the list of SKUs in memory. Enter Get-MgSubscribedSku
.
$skus = Get-MgSubscribedSku
$skuHash = @{}
foreach ($sku in $skus) {
$skuHash[$sku.SkuId] = $sku
}
Putting it together
Ok. We’ve got a few things going for us now. Let’s slap it together and see if we can make something out of it. It’s likely that I won’t be hooking all these pieces together for each post, but I’ll leave it with a simple example. Use it for inspiration.
$output = @()
# Get your users. Probably not like this.
$users = Get-MgUser -All # There's nuance here...
foreach ($user in $users) {
$assignedLicenses = Get-MgUserLicenseDetail -UserId $user.Id
foreach ($assignedLicense in $assignedLicenses) {
$license = $skuHash[$licenseDetail.SkuId]
$output += [PSCustomObject]@{
DisplayName = $user.DisplayName
UPN = $user.UserPrincipalName
SkuPartNumber = $license.SkuId
SkuId = $license.SkuId
}
}
}
$output | format-list
So with this primitive example you may have enough to set you on the right path. Anyone who has worked MS Graph for any length of time has found that there are things that have changed and there are gaps in knowledge that you may need to cross. Maybe this is a little bit of a boost but there will be at least one follow up to this. Writing and improving and adding features and optimizing scripts and reporting can be a bit of a rabbit hole.
./content/posts/m365-licensing-with-graph-ps-module.md 1:1 suggestion You averaged 1.05 complex marktoso.Kiss words per sentence 9:322 warning Use first person (such as Microsoft.FirstPerson 'My') sparingly. 9:342 suggestion 'be focused' looks like Microsoft.Passive passive voice. 9:360 warning Consider removing 'fairly'. Microsoft.Adverbs 13:288 warning Consider removing 'Seriously'. Microsoft.Adverbs 13:386 warning Consider removing 'fairly'. Microsoft.Adverbs 13:465 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 13:509 warning Try to avoid using Microsoft.We first-person plural like 'We'. 16:1 warning Try to avoid using Microsoft.We first-person plural like 'We'. 16:1 error Use 'we've' instead of 'We Microsoft.Contractions have'. 16:143 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 16:144 suggestion Try to keep sentences short (< Microsoft.SentenceLength 30 words). 16:204 suggestion 'was standardized' looks like Microsoft.Passive passive voice. 16:279 warning Consider using 'all' instead Microsoft.Wordiness of 'all of'. 18:61 suggestion 'be applied' looks like Microsoft.Passive passive voice. 18:122 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 18:140 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 18:204 suggestion 'being democratized' looks Microsoft.Passive like passive voice. 18:253 warning Try to avoid using Microsoft.We first-person plural like 'our'. 18:290 suggestion Consider using 'part' instead Microsoft.ComplexWords of 'component'. 18:300 error Use 'isn't' instead of 'is Microsoft.Contractions not'. 18:317 warning Try to avoid using Microsoft.We first-person plural like 'We'. 18:342 warning Consider removing 'regularly'. Microsoft.Adverbs 18:359 warning In general, don't use an Microsoft.Ellipses ellipsis. 18:381 warning Try to avoid using Microsoft.We first-person plural like 'let's'. 21:19 warning Try to avoid using Microsoft.We first-person plural like 'we'. 21:165 warning Try to avoid using Microsoft.We first-person plural like 'We'. 21:279 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 21:291 warning Try to avoid using Microsoft.We first-person plural like 'We'. 21:301 warning Try to avoid using Microsoft.We first-person plural like 'We'. 21:328 warning Try to avoid using Microsoft.We first-person plural like 'we'. 23:24 warning Try to avoid using Microsoft.We first-person plural like 'our'. 24:1 warning Try to avoid using Microsoft.We first-person plural like 'We'. 24:38 warning Try to avoid using Microsoft.We first-person plural like 'we'. 24:182 error More than 3 commas! marktoso.TresComas 24:208 suggestion Verify your use of 'allow' Microsoft.Vocab with the A-Z word list. 24:214 warning Try to avoid using Microsoft.We first-person plural like 'us'. 24:291 warning Try to avoid using Microsoft.We first-person plural like 'we'. 34:25 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 35:28 warning Consider removing 'very'. Microsoft.Adverbs 35:78 warning Try to avoid using Microsoft.We first-person plural like 'us'. 35:86 warning Try to avoid using Microsoft.We first-person plural like 'we'. 35:204 warning Use first person (such as Microsoft.FirstPerson 'my') sparingly. 35:218 warning Consider removing Microsoft.Adverbs 'wonderfully'. 35:295 warning Try to avoid using Microsoft.We first-person plural like 'we'. 35:375 warning Try to avoid using Microsoft.We first-person plural like 'we'. 35:393 warning Try to avoid using Microsoft.We first-person plural like 'we'. 35:643 warning Try to avoid using Microsoft.We first-person plural like 'we'. 37:37 warning Try to avoid using Microsoft.We first-person plural like 'we'. 37:48 warning Try to avoid using Microsoft.We first-person plural like 'our'. 37:129 suggestion Try to keep sentences short (< Microsoft.SentenceLength 30 words). 37:138 warning Try to avoid using Microsoft.We first-person plural like 'we'. 37:149 warning Try to avoid using Microsoft.We first-person plural like 'our'. 37:194 error Use 'that's' instead of 'that Microsoft.Contractions is'. 37:231 warning Try to avoid using Microsoft.We first-person plural like 'our'. 37:373 warning Try to avoid using Microsoft.We first-person plural like 'we'. 37:399 warning Consider using 'many' instead Microsoft.Wordiness of 'a large number of'. 37:424 warning Try to avoid using Microsoft.We first-person plural like 'we'. 47:5 warning Try to avoid using Microsoft.We first-person plural like 'We'. 47:38 warning Try to avoid using Microsoft.We first-person plural like 'us'. 47:46 warning Try to avoid using Microsoft.We first-person plural like 'Let's'. 47:80 warning Try to avoid using Microsoft.We first-person plural like 'we'. 47:129 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 66:82 suggestion Try to keep sentences short (< Microsoft.SentenceLength 30 words). 69:21 suggestion 'was checked' looks like Microsoft.Passive passive voice. 69:127 suggestion 'was checked' looks like Microsoft.Passive passive voice. 69:165 suggestion Verify your use of 'as well Microsoft.Vocab as' with the A-Z word list. 69:191 warning Use first person (such as ' I Microsoft.FirstPerson ') sparingly. 69:265 suggestion 'was put' looks like passive Microsoft.Passive voice.✖ 4 errors, 51 warnings and 14 suggestions in 1 file.