Assign M365 license via Graph PowerShell SDK

If you are looking for a easier and a faster way to assign M365 license, then you have landed on the right page.  Instead of using the M365 admin portal, Microsoft Graph PowerShell SDK is the new shiny tool to automate the assignment of license.

What is Graph PowerShell SDK

Microsoft Graph PowerShell Module consists of a collection of PowerShell modules that contain commands for calling Microsoft Graph API. The module acts as an API wrapper for the Microsoft Graph APIs, exposing the entire API set for use in PowerShell.

Microsoft Graph PowerShell is the replacement for the Azure AD PowerShell and MSOnline modules and is recommended for interacting with Azure AD.

Prerequisites for installing Graph PowerShell SDK

To install PowerShell 7 run the command below:

The install is simple, just one line. Run the command below

iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI"

Install Graph PowerShell SDK

To install Microsoft Graph PowerShell SDK, run the command below

Install-Module Microsoft.Graph -Scope CurrentUser -AllowClobber -Force

Verify graph Install

To confirm the installation of Microsoft Graph PowerShell SDK, run the command below. Microsoft.Graph is the name of the PowerShell module.

Get-InstalledModule Microsoft.Graph

Ok, after getting the prerequires out the way, it’s time to get into the fun stuff. Since the objective is to automate the assignment of M365 licenses, we need to create a service principle (App registration) in Azure AD. The steps are listed below.

Create App Registration in Azure AD

Log into the Azure portal and navigate to Azure Active Directory > App registration > and click on New registration and enter the requested information.

  • Name – enter the name of the application
  • Supported account types – select Accounts in this organizational directory only (only – Single tenant)
  • Redirect URI (optional) – Select Web > URL address = http://localhost > then click register

After the application is created, write down the:

Application Client ID = 9217dj74r-cqp3-42b2-a79d-392394ad7na8 and the
Directory tenant ID = 40187a2a4-c7b8-4d2e-99f1-pnc4ca1502xu (those ID’s are not real)

You will need those values later on when connecting to Graph.

Create the application Secret:

Under Manage click on Certificates & secrets > then click on New client secret

Enter a description and an expiration date.  The default is 6 months > then click Add

Remember to write down the Secret Value and the Secret ID. Once you leave the page, you will no longer have access to it. The examples below are fake. The secret will be used to connect to graph. We still have a few more configuration steps before we can connect to graph.

Secret Value: bz177~FSYPwjQKuyq-ulKh~fvZvQWFmFpuj765ut5gf
Secret ID: Pw785d43b2c-7e9f-416f-bec7-q43013589hbg6j

Configure application permission

We will choose application permission to support full automation. Since we are still under the applications settings, click on API permissions > Add a permission

Click on Microsoft Graph

Click on Application permissions:
Organization.Read.All permission scope is required to read the licenses available in the tenant. Also editing user license assignment require User.ReadWrite.All and Directory.ReadWrite.All

Link to Application Permissions

Select the suggested permissions listed above and click on Add permission

The result should look like this:

The next step is to grant admin consent. Click on Grant admin consent for “your org” and confirm

The Status should change to Green

Instead of using a secret for authentication, you can also a certificate which is more secure. If you do not have access to a PKI cert, you can create a self-signed cert.

Create self-signed certificate:

#Creating self-signed certificate
$CertParam = @{
    'KeyAlgorithm'      = 'RSA'
    'KeyLength'         = 2048
    'KeyExportPolicy'   = 'NonExportable'
    'DnsName'           = 'DESKTOP-CompName'
    'FriendlyName'      = 'AutomateGraphApp_Test44'
    'CertStoreLocation' = 'Cert:\CurrentUser\My\'
    'NotAfter'          = (Get-Date).AddYears(1)
}
 
#Creating self signed cert with parameters from above.
$Cert = New-SelfSignedCertificate @CertParam
 
#view cert
$Cert | Select Subject, Thumbprint, FriendlyName
 
#Export the .cer and upload to Azure
Export-Certificate -Cert $Cert -FilePath C:\AssignLicense\AutomateApp_test.cer 

Connect to Graph using a certificate

The Appid, TenantID and certificate values are fake for example.

$AppId = 'uqorfc34-c2d3-42b2-a79d-rt453218a1433'
$TenantId = 'hh67ds342a4-c7b8-4d2e-99f1-cc881ca150bia3'
$Certificate = Get-ChildItem Cert:\CurrentUser\My\11dd66nn33904F38516DCED11379AFE5C20867gf32d  
Connect-Graph -TenantId $TenantId -AppId $AppId -Certificate $Certificate

If successful the screen will say, “Welcome of Microsoft Graph!”

Connect to Graph using client secret

#Install MSAL.PS module for all users (requires admin rights)
Install-Module MSAL.PS -Scope AllUsers -Force
 
#Generate Access Token to use in the connection string to MSGraph
$AppId = '49gf3w24c-c2d3-42b2-a79d-392394a7hh32'
$TenantId = 'ss8k75f2a4-c7b8-4d2e-99f1-f3c4cafj6mq8hr5'
$ClientSecret = 'bb.81g~FSYyyh85KvQv-ulKh~fvZvQWFmFp11fk83g'
 
Import-Module MSAL.PS
$MsalToken = Get-MsalToken -TenantId $TenantId -ClientId $AppId -ClientSecret ($ClientSecret | ConvertTo-SecureString -AsPlainText -Force)
 
#Connect to Graph using access token
Connect-Graph -AccessToken $MsalToken.AccessToken

Select the Graph Profile

By default the Microsoft Graph PowerShell commands target the v1.0 API version. Commands for APIs that are only available in beta aren’t available in PowerShell by default. If you run into errors running the script below, just change the Graph profile to beta. The GA version of Graph is v1.0 and the preview version is Beta.

To view the current version, use the Get command. To change the current version, use the Select command below. See the commands below

#displays the current version
Get-MgProfile 
#change the current version
 Select-MgProfile -Name Beta #or v1.0 

PowerShell Script

Customers upgrade from O365 E3 to M365 E5 licenses all the time. Below you will find an example script to remove the old license and add the new M365 E5 license. I hope this helps.

# connect to Graph Service
$AppId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$TenantId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$Certificate = Get-ChildItem Cert:\CurrentUser\My\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  #that is the thumbprint
Connect-Graph -TenantId $TenantId -AppId $AppId -Certificate $Certificate

#Set Graph Profile
Select-MgProfile -Name beta

#Get the SKU and plan info
$O365g3Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'ENTERPRISEPACK_GOV'
$O365g3SkuEXDisabled = $O365g3Sku.ServicePlans | Where ServicePlanName -in ("EXCHANGE_S_ENTERPRISE_GOV") | Select -ExpandProperty ServicePlanId
$M365g3Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq 'M365_G3_GOV'

#Export User types for documentation pre-run
Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($O365g3Sku.SkuId) )" -ConsistencyLevel eventual -CountVariable e5licensedUserCount -All | Select ID, DisplayName, UserPrincipalName | Export-Csv c:\temp\All_G3_Users_PreRun.csv
#get the exchange disabled users here

#Get users with G3 license (all users)
$G3Users = Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($O365g3Sku.SkuId) )" -ConsistencyLevel eventual -CountVariable e5licensedUserCount -All

# Unassign E3, Assign M3
Foreach ($User in $G3Users) {

    Set-MgUserLicense -UserId $User.ID -AddLicenses @{} -RemoveLicenses @($O365g3Sku.SkuId)
    Set-MgUserLicense -UserId $User.ID -AddLicenses @{ SkuId = M365g3Sku.SkuId } -RemoveLicenses @()
}

THE END 🙂

Author