Automatically Provision New Office 365 Mailboxes

Transitioning from an on-premise messaging solution to Exchange Online is often only half the battle.  A long-term administration strategy is just as important as a sound migration plan.  Many organizations use identity management software to on-board new employees, and any reputable product can easily create AD accounts and assign the necessary attributes to mail-enable the object.  However, even after DirSync picks up the new object and creates it in O365, assigning the appropriate license and provisioning the Exchange Online mailbox is still a manual process.  So, I set out to automate mailbox provisioning using export files generated by IDM solutions.

To begin, I created a file share on the Exchange 2010 CAS where IDM can write its export files.  Now, each time new users are created in AD, the data is written to CSV files on the IDM share.  The contents of the export file include CN (Name), UserPrincipalName (Upn), and EmployeeType.  The employee type (or a similar identifier) will be used to determine which O365 license gets assigned.

Now, let's begin developing the script.  First, we need to connect to O365.  The script will be running as a scheduled task, so, I need to include the O365 credentials without prompts.  I describe the steps for creating a secure password file in a previous post:

$Username = "admin@domain.onmicrosoft.com"

$Password = Get-Content c:\o365\remoteps.pwd | ConvertTo-SecureString

$Credential = New-Object System.Management.Automation.PSCredential($Username,$Password)

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell" -Credential $Credential -Authentication Basic -AllowRedirection

$ImportResults = Import-PSSession $Session

Import-Module MSOnline

Connect-MSOLService -Credential $Credential

I'll set a timestamp that can be used to identify each processing run:

$TimeStamp = Get-Date -Format "yyMMddhhmmss"

Next, well read all the CSV export files created by the identity management solution and write the aggregated results into a temporary file:

Get-ChildItem -Path c:\IDM\*.csv | ForEach { Import-Csv $_ } | Export-Csv -NoTypeInformation "c:\IDM\$TimeStamp.tmp"

Once all the CSV export files are processed, we'll move the original files to a Processed folder along with any old log files:

Move-Item "c:\IDM\*.csv" "c:\IDM\Processed"

Move-Item "c:\IDM\*.log" "c:\IDM\Processed"

And then we'll create a new export file and log file to save our provisioning results:

$ExportFile = "c:\IDM\$TimeStamp.csv"

"CN,EmployeeType,UserPrincipalName" | Out-File $ExportFile

$LogFile = "c:\IDM\$TimeStamp.log"

Now, let's do some work!  We will import the temporary CSV file that contains the aggregated data from each of the IDM export files and set some variables:

Import-Csv "c:\IDM\$TimeStamp.tmp" | ForEach {

$Name = $_.CN; $Type = $_.EmployeeType

$Upn = $_.UserPrincipalName

$CheckMailbox = $null; $CheckMailUser = $null

For each user, we will run Get-Mailbox to check if a mailbox already exists in O365.  If a mailbox cannot be found, the cmdlet will error out and the $CheckMailbox variable will remain null.

$CheckMailbox = Get-Mailbox $Upn

If there is no mailbox already provisioned for the user, we run Get-MsolUser to check if the account has been mail-enabled and synchronized to O365.  Once again, if the account has not been successfully mail-enabled, then the cmdlet will error out and the $CheckMailUser variable will remain null.

If ($CheckMailbox -eq $null) {

  $CheckMailUser = Get-MsolUser -User $Upn

If the new account has been successfully mail-enabled, then we'll set the usage location and assign an O365 license.  In this example, I am using the EmployeeType column from the IDM export files to determine whether the user gets an Exchange Standard license or a Kiosk license.  We'll also write the results to a log file:

If ($CheckMailUser -ne $null) {

   Set-MsolUser -User $Upn -UsageLocation US

   If ($Type -eq "E") {

     Set-MsolUserLicense -User $Upn -AddLicenses "tenant:EXCHANGESTANDARD"

     "SUCCESS: New user account provisioned with Plan1 mailbox [$Upn]" |
Out-File $LogFile -Append }

   If ($Type -eq "N") {

     Set-MsolUserLicense -User $Upn -AddLicenses "tenant:EXCHANGEDESKLESS"

     "SUCCESS: New account provisioned with Kiosk mailbox [$Upn]" |
Out-File $LogFile -Append }

After assigning the license, we will run Test-MapiConnectivity which seems to help initialize newly created mailboxes:

  Test-MapiConnectivity $Upn }

Finally, we'll write data to the log file if the account was not mail-enabled.  It's possible, however, that DirSync has not yet run for the newly created account.  So, instead of discarding the user, I will write the data to a new CSV file so that it can be processed again.

  Else {

    "ERROR: New account not synchronized to O365 [$Upn]" | Out-File
$LogFile -Append

    "$Name,$Type,$Upn" | Out-File $ExportFile -Append } }

I will also write to the log if an O365 mailbox already existed for the user.

Else { "ERROR: O365 mailbox already exists for new user account [$Upn]" |
Out-File $LogFile -Append } }

As a bonus, we can email the log file to a user (or group of users) for review:

$SmtpServer = "smtp.domain.com"

$Smtp = New-Object Net.Mail.SmtpClient($SmtpServer)

$SmtpFile = New-Object Net.Mail.Attachment($LogFile)

$SmtpMsg = New-Object Net.Mail.MailMessage

$SmtpMsg.From = "admin@domain.com"

$SmtpMsg.To.Add("user@domain.com")

$SmtpMsg.Subject = "New Mailbox Provisioning"

$SmtpMsg.Body = "Attached is the latest O365 mailbox provisioning log."

$SmtpMsg.Attachments.Add($SmtpFile)

$Smtp.Timeout = "30000"

$Smtp.Send($SmtpMsg)

And as a best practice, we will gracefully disconnect our remote PowerShell session.  I am also deleting our temporary file and "releasing" the log file.

Remove-PSSession -Session $Session

Remove-Item "c:\IDM\$TimeStamp.tmp"

$SmtpFile.Dispose()

Now, the script can be run periodically as a scheduled task.  Here is a summary of what it actually does...

  1. Establish remote PowerShell session to MSO
  2. Read all CSV files on IDM share and aggregate data into single temp CSV
  3. Move all processed CSV file(s) to Processed directory on IDM share
  4. Read consolidated data from temp CSV and check if mailbox may already exist
  5. If mailbox does not exist, check if accounts have been mail-enabled and synchronized to O365
  6. If accounts have been mail-enabled, assign Plan1 or Kiosk license according to EmployeeType and provision mailbox
  7. Write any failed or skipped users to new CSV file on IDM share
  8. Write log file and email to administrator for review
  9. Delete temp CSV file

On subsequent runs, the script will read any new CSV files IDM has exported to the share, plus the CSV created for any failed or skipped users... and the whole process repeats.  RjZ

AutoProvisionMailbox.zip