Automatically manage Office 365 Licences with Powershell

Managing Office 365 manually via the portal is fine, until you get fed up with it or need to make bulk changes. Automating the licence allocation process turned out to be fairly easy, once I’d got to grips with how the PowerShell cmdlets worked.

This is nothing massively complex. My top tips are:

  1. Make sure that you only ever specify “valid” combinations of licences – e.g. you can’t add Audio Conferencing if the user doesn’t have a Skype for Business licence. This is exactly the same as when you manage users via the Admin portal.
  2. Get to grips with the terminology:
    1. AccountSkuId = a code for a top level product as seen in the admin portal, for example O365_BUSINESS_PREMIUM is the Office 365 Business Premium bundle.
    2. Plans = subcomponents of an AccountSkuId, e.g. MICROSOFTBOOKINGS is (unsurprisingly) Microsoft Bookings. By default, all plans within an AccountSkuId are enabled when you add an AccountSkuId to a user. To disable some, you create an MsolLicenseOptions object specifying the plans you want disabled.
  3. To change the plans that are enabled/disabled within an AccountSkuId for a user, you have to remove the AccountSkuId from the user, create the MsolLicenseOptions object and then re-add the AccountSkuId specifying the MsolLicenseOptions object.
  4. For the Msol PowerShell cmdlets, it’s “License” not “Licence”!

I’ve been meaning to do this for some time, it just feels like it should be automated, and now, for me, it is.

What it does

The script below runs as a scheduled task. It writes its actions to the Application event log. The way it works is to assume that all users in Office 365 should have a Business Premium licence, unless they’re a member of an Office 365 security group called “Unlicensed Users”. If they’re in that group, it removes all licences from them.

Events logged are as follows:

  • 10003 – Start processing O365 Licenses
  • 10004 – Finish processing O365 Licenses
  • 10001 – Removed license from <User>
  • 10002 – Added license to <User>
  • 10005 – Failed to remove license from <User>
  • 10006 – Failed to add license to <User>

It’s easy to filter the event log to see just the information you’re looking for, to confirm what actions have been taken, and when.


The scheduled task is set to run as a user, and I’ve created an encrypted password file whilst running as that user, the password is for the Office 365 Global Admin account that’ll be used by the script. To create the password file, use:

runas /user:<domain>\scheduled-task-user

to run a powershell prompt on the machine where the scheduled task will be run. The within that PowerShell prompt run the following:

Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File -FilePath "C:\Users\aacsyncuser\Documents\GlobalAdmin.pass"

and provide the Office 365 Global Admin password when prompted. This will create the .pass file used by the script.

Then from an Administrator PowerShell prompt, run the following to create the Event Log source used by the script:

New-EventLog -LogName Application -Source "Manage O365 Licenses"

Grant the scheduled task user the “Log on as a batch job” right: From your Administrator prompt, run gpedit.msc and go to Local Computer Policy – Computer Configuration – Windows Settings – Security Settings – Local Policies – User Rights Assignment. Double-click Logon on as a batch job and add the scheduled task user.

Make sure the machine running the scheduled task has the following installed:

Save the script and modify it to include the correct path to the password file you created, the correct Global Admin UPN for $MsolGlobalAdminUsername, and your MSOL Domain name for $MsolDomain.

Import-Module MSOnline

$EncryptedPasswordFile = "C:\Users\aacsyncuser\Documents\GlobalAdmin.pass"
$MsolGlobalAdminUsername = ""
$SecureStringPassword = Get-Content -Path $EncryptedPasswordFile | ConvertTo-SecureString
$MsolCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $MsolGlobalAdminUsername,$SecureStringPassword

Connect-MsolService -Credential $MsolCred

Write-EventLog -LogName Application -Source "Manage O365 Licenses" -EntryType Information -EventId 10003 -Message ("Start processing O365 Licenses")

$MsolDomain = "RCMTECHCOUK"

# Remove products from users in the "Unlicensed Users" group
$UnlicensedUsersGroupGUID = (Get-MsolGroup -GroupType Security | Where-Object -Property DisplayName -EQ "Unlicensed Users").ObjectID.Guid
$UnlicensedUsers = (Get-MsolGroupMember -GroupObjectId $UnlicensedUsersGroupGUID).EmailAddress
foreach($User in $UnlicensedUsers){
    $AccountLicenses = (Get-MsolUser -UserPrincipalName $User).Licenses
    if($AccountLicenses.Count -gt 0){
        Write-Host ("Remove license from "+$User)
            Set-MsolUserLicense -UserPrincipalName $User -RemoveLicenses $AccountLicenses.AccountSkuId # Remove all products
            Write-EventLog -LogName Application -Source "Manage O365 Licenses" -EntryType Information -EventId 10001 -Message ("Removed license from "+$User)
            Write-EventLog -LogName Application -Source "Manage O365 Licenses" -EntryType Warning -EventId 10005 -Message ("Failed to remove license from "+$User)

# Set license options
$MsolAccountSkuIdsToAdd = $MsolDomain+":O365_BUSINESS_PREMIUM"
$MsolLicenseOptions = New-MsolLicenseOptions -AccountSkuId $MsolAccountSkuIdsToAdd -DisabledPlans "EXCHANGE_S_STANDARD","MICROSOFTBOOKINGS","O365_SB_Relationship_Management"

# Add licenses to all users who currently do not have a licence as long as they're not in the "Unlicensed Users" group
$AllUnlicensedUsers = Get-MsolUser | Where-Object -Property IsLicensed -EQ $false
foreach($User in $AllUnlicensedUsers){
    if($UnlicensedUsers -notcontains $User.UserPrincipalName){
        Write-Host ("Add license to "+$User.UserPrincipalName)
            Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses $MsolAccountSkuIdsToAdd -LicenseOptions $MsolLicenseOptions
            Write-EventLog -LogName Application -Source "Manage O365 Licenses" -EntryType Information -EventId 10002 -Message ("Added license to "+$User.UserPrincipalName)
            Write-EventLog -LogName Application -Source "Manage O365 Licenses" -EntryType Warning -EventId 10006 -Message ("Failed to add license to "+$User.UserPrincipalName)

Write-EventLog -LogName Application -Source "Manage O365 Licenses" -EntryType Information -EventId 10004 -Message ("Finish processing O365 Licenses")
This entry was posted in Office 365, PowerShell and tagged , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.