Using PowerShell to automate Office 365 license assignment

The move to Office 365 almost always requires changes to existing operational processes. One of the processes that inevitably requires an update is the provisioning process and the extent of these changes will differ from organization to organization and depend on the maturity of your identity lifecycle management process. In many environments, license assignment can be easily automated using a scheduled task and PowerShell so I wanted to put together a post that provides an outline on how this can be done.

Before getting into it, I just want to add a little disclaimer to this post – I love PowerShell and because I love PowerShell, I like to use it, but this doesn’t mean it is always fit for purpose. Each environment is different so I would urge you to consider all options before implementing a full blown PowerShell provisioning process because you may already own better tools for the job (FIM/MIM, etc). These tools often take a while to implement when done properly, so PowerShell could also be a great stop-gap solution. This post is intended to provide a foundation that helps you put together your own process and should not necessarily be implemented “as-is”.

With that out of the way, there are some requirements to think of as well. The server executing the script will need the following:

The scenario I will be addressing in this post is to automate mailbox provisioning and license assignment in a hybrid deployment. All new mailboxes get provisioned as remote mailboxes directly in Office 365 and users are assigned the relevant Office 365 license. Each user account has an entry in the ‘extensionAttribute1’ attribute which determines the license they will be assigned, eg. E3 or Exchange Plan 2. We make use of 2 security groups during this process so users can be created in any OU as long as that OU is being synchronized to Azure AD. These groups are:

O365_Provision – Starts the provisioning process. New accounts are added to this group once they have been created in Active Directory

O365_License – Used by the script to keep track of users who still need to have licenses assigned

At a high level the workflow looks something like this:

Lets start by looking at the variables and functions we need. Here you can define you license SKUs, service account credentials, etc:

Next we have the ‘licensing phase’ – This phase also generates the email report because a user is considered to be fully provisioned once they have a license assigned. We can also catch any errors and generate an error report email for those.

The ‘mailbox enablement phase’ connects to the local Exchange server and creates a new remote mailbox. See this post for more information on this process. This phase also attempts to generate error notification emails.

# Mailbox Enablement Phase - Check if any new mailboxes need to be provisioned$NeedMailbox=Get-AdGroupMember-IdentityO365_ProvisioningIf($NeedMailbox){Connect-ExchangeForeach($Userin$NeedMailbox){$Username=$User.SamAccountName$UserInfo=Get-ADUser$Username-Properties*$UserLic=$UserInfo.extensionAttribute1$UserLoc=$UserInfo.cIf($UserLic-and$UserLoc){Try{Enable-RemoteMailbox$Username-RemoteRoutingAddress"$Username@$RoutingDomain"Add-ADGroupMember-IdentityO365_License-Members$UsernameRemove-AdGroupMember-IdentityO365_Provisioning-Members$Username-Confirm:$False}Catch{$EmailSubject='Office 365 Provisioning Error'$EmailBody=@"
<html>
<head>
</head>
<body>
Hello,
This is an automated report from the Office 365 Provisioning Service. The following errors occurred when attempting to mail-enable users:
<span style="color:#B22222;">$Error</span><strong>AdditionalDiagnosticInfo:</strong>Username:$UsernameRegards,ProvisioningService</body>
</html>"@
Send-Report
}
}
Else {
$EmailSubject = 'Office 365 Provisioning Error'
$EmailBody = @"<html><head></head>
<body>
Hello,
This is an automated report from the Office 365 Provisioning Service. The following user could not be provisioned, please check to ensure that the required license type has been correctly entered in the "Company" field and that the "Country/region" has been set:
<span style="color:#B22222;">User: $Username</span>Regards,ProvisioningService</body>
</html>"@
Send-Report
}
}
}

Putting this all together will hopefully form be a great foundation to help you build your own workflow. Once done, you can simply schedule your script to run using task scheduler.