Implementing Office 365 in a production environment you most often end up with quite a few scheduled scripts for licensing, shared mailbox maintenance and other similiar tasks. When moving more and more services to the cloud, moving from infrastructure services to platform services is the way of nature.
One service that can help you to get more efficient when it comes to scheduling scripts is Azure Automation. Instead of having a server where you schedule your scripts, you simply schedule them within the automation service that takes care of the rest. As of now, Azure Automation does not support use of the Azure Active Directory Powershell module, which means we cannot use the service for our licensing scripts. Make sure to vote for the suggestion to fix that here.
Exchange Online, Lync Online and SharePoint Online do however work well, so that’s what my example is going to be about. To make it easy for me I’m using a script from one of my older posts about Dynamically adding mailbox permissions through groups, with some adjustments to fit Azure Automation.
1. First of all, if you don’t already have one, you need an Azure Automation account. I’m choosing to create mine in the West Europe region. By default, it will use a free automation plan that gives you 500 minutes of job runtime per month.

2. Now create an asset/setting that will store your Exchange Online admin credentials in a secure way. We will call the asset ‘EXOCreds’ so we easliy can pick them up later in the script.


3. Create a runbook in the automation account you created earlier, in my case I called it ‘Sync-EXOSharedMailboxPermissions’.

4. Now it’s time to author the runbook, in my example I’ve just changed some minor things with parameters and credentials. If you’re a PowerShell WF Pro, there might be a lot of things you can do to improve the script.

Below you’ll find the code I’ve used:
Sync-EXOSharedMailboxPermissions
workflow Sync-EXOSharedMailboxPermissions {
<#
.SYNOPSIS
The script will automatically assign mailbox and recipient permissions on shared mailboxes based on groups.
Modified 2015-04-05 to support Azure automation and PowerShell workflows
.NOTES
File Name: SharedMailboxViaGroups.ps1
Author : Johan Dahlbom, johan[at]dahlbom.eu
Blog : 365lab.net
The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights.
Requires PowerShell Version 3.0!
#>
#Credentials to connect to Exchange Online
$Credentials = Get-AutomationPSCredential -Name 'EXOCreds'
#Prefix to search for
$Prefix = 'SM-'
function Connect-ExchangeOnline {
param (
$Creds
)
#Clean up existing PowerShell Sessions
Get-PSSession | Remove-PSSession
#Connect to Exchange Online
$Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Creds -Authentication Basic -AllowRedirection
$Commands = @("Add-MailboxPermission","Add-RecipientPermission","Remove-RecipientPermission","Remove-MailboxPermission","Get-MailboxPermission","Get-User","Get-DistributionGroupMember","Get-DistributionGroup","Get-Mailbox")
Import-PSSession -Session $Session -Prefix "Cloud" -DisableNameChecking:$true -AllowClobber:$true -CommandName $Commands | Out-Null
}
Connect-ExchangeOnline -Creds $Credentials
inlineScript {
function Add-JDMailboxPermission {
param(
[string]$Identity,
[string]$SharedMailboxName
)
try {
Add-CloudMailboxPermission -Identity $SharedMailboxName -User $Identity -AccessRights FullAccess -ErrorAction stop | Out-Null
Add-CloudRecipientPermission -Identity $SharedMailboxName -Trustee $Identity -AccessRights SendAs -Confirm:$False -ErrorAction stop | Out-Null
Write-Output "INFO: Successfully added $Identity to $SharedMailboxName"
} catch {
Write-Warning "Cannot add $Identity to $SharedMailboxName`r`n$_"
}
}
function Remove-JDMailboxPermission {
param(
[string]$Identity,
[string]$SharedMailboxName
)
try {
Remove-CloudMailboxPermission -Identity $SharedMailboxName -User $Identity -AccessRights FullAccess -Confirm:$False -ErrorAction stop -WarningAction ignore | Out-Null
Remove-CloudRecipientPermission -Identity $SharedMailboxName -Trustee $Identity -AccessRights SendAs -Confirm:$False -ErrorAction stop -WarningAction ignore | Out-Null
Write-Output "INFO: Successfully removed $Identity from $SharedMailboxName"
} catch {
Write-Warning "Cannot remove $Identity from $SharedMailboxName`r`n$_"
}
}
function Sync-EXOResourceGroup {
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[string]$Prefix = 'SM-'
)
#Get All groups to process mailboxes for
$MasterGroups = Get-CloudDistributionGroup -ResultSize Unlimited -Identity "$Prefix*"
foreach ($Group in $MasterGroups) {
#Remove prefix to get the mailbox name
$MbxName = $Group.Name.Replace("$Prefix",'')
$SharedMailboxName = (Get-CloudMailbox -Identity $MbxName -ErrorAction ignore -WarningAction ignore).WindowsLiveID
if ($SharedMailboxName) {
Write-Verbose -Message "Processing group $($Group.Name) and mailbox $SharedMailboxName"
#Get all users with explicit permissions on the mailbox
$SharedMailboxDelegates = Get-CloudMailboxPermission -Identity $SharedMailboxName -ErrorAction Stop -ResultSize Unlimited | Where-Object {$_.IsInherited -eq $false -and $_.User -ne "NT AUTHORITY\SELF" -and $_.User -notmatch 'S-\d-\d-\d+-\d+-\d+-\d+-\w+' -and $_.User -notlike "$Prefix*"} | Select-Object @{Name="User";Expression={(Get-CloudUser -identity $_.User).WindowsLiveID }}
#Get all group members
$SharedMailboxMembers = Get-CloudDistributionGroupMember -Identity $Group.Identity -ResultSize Unlimited
#Remove users if group is empty
if (-not($SharedMailboxMembers) -and $SharedMailboxDelegates) {
Write-Warning "The group $Group is empty, will remove explicit permissions from $SharedMailboxName"
foreach ($user in $SharedMailboxDelegates.User) {
Remove-JDMailboxPermission -Identity $user -SharedMailboxName $SharedMailboxName
}
#Add users if no permissions are present
} elseif (-not($SharedMailboxDelegates)) {
foreach ($user in $SharedMailboxMembers.WindowsLiveID) {
Add-JDMailboxPermission -Identity $user -SharedMailboxName $SharedMailboxName
}
#Process removals and adds
} else {
#Compare the group with the users that have actual access
$Users = Compare-Object -ReferenceObject $SharedMailboxDelegates.User -DifferenceObject $SharedMailboxMembers.WindowsLiveID
#Add users that are members of the group but do not have access to the shared mailbox
foreach ($user in ($users | Where-Object {$_.SideIndicator -eq "=>"})) {
Add-JDMailboxPermission -Identity $user.InputObject -SharedMailboxName $SharedMailboxName
}
#Remove users that have access to the shared mailbox but are not members of the group
foreach ($user in ($users | Where-Object {$_.SideIndicator -eq "<="})) {
Remove-JDMailboxPermission -Identity $user.InputObject -SharedMailboxName $SharedMailboxName
}
}
} else {
Write-Warning "Could not find the mailbox $MbxName"
}
}
}
#Start Processing groups and mailboxes
Sync-EXOResourceGroup -Prefix $Using:Prefix -Verbose
}
}
5. Test the runbook by clicking the test button. You will be asked to save the runbook before you test. Hopefully your output will be as nice looking as mine. 🙂

6. If all went good, you’re now ready to publish and schedule the runbook. I’m choosing to schedule mine to run every three hours. Depending on your script runtime, you might want to change this due to cost or other factors. (Remember your free 500 minutes!)







My runbook is now published and scheduled, now it’s just to wait for the magic to happen. Hope this gives you an idea what Azure Automation can do for you!
Additional resources to get started can be found below:
Get Started with Azure Automation
Automating the Cloud with Azure Automation (MVA)
Until next time! 🙂
/Johan