Office 365 Email Address Policies with Azure Automation

Office 365 Email Address Policies with Azure Automation

Email address policies (EAP) define the rules that create email addresses for recipients. By setting up policies you can guarantee your users will have certain email address that follow the rules you have set in place. Unfortunately, in Office 365 Exchange Online there are no email address policies you can set for your users. In a larger organization where multiple people may be creating and editing users in Exchange Online, it’s possible that not all your users are following the address scheme you or your company has implemented. In this article I will leverage PowerShell and Azure RunBooks to make sure all of my users adhere to my companies EAP.

Setting up the Azure Automation Resources

In the next section I will go over what Azure resources we will be creating and what each one is responsible for. You can skip ahead to the configuration script below which will create your Azure resources for you.

Runbook

The runbook will contain all of our PowerShell code that will be used to connect to Exchange Online, parse all of the users, and modify their proxyaddresses to adhere to our EAP. Think of the runbook as a PowerShell script. Azure Automation allows us to edit, publish and even test our runbook.

Automation Account

The automation account runs our runbook, stores our credentials and also contains which PowerShell modules are available to use in the runbook.

Automation Credential

The automation credential will contain the credentials our runbook will use to connect to Exchange Online. Automation Credentials are stored securely in Azure Automation

Resource Group

The resource group will contain all of our assets in one collection. You can use an existing resource group or have PowerShell create a new one for you. If the resource group is not found, PowerShell will automatically provision a new one.

Create all your Automation Resources with PowerShell

The following PowerShell script will create everything mentioned above. For the AutomationCredUser and AutomationCredPassword I recommend you creating a separate service account and NOT use an active user account. If the account has MFA enabled (which it should!) then enter an app password.

In my example my automation account is going to be named: EXOAutomationAccount. The Runbook will be named “Office_365_EAPRunbook“, the resource group that contains all my assets will be called rg-psautomation, the locations for my assets will be North Central US. My automation user is [email protected] with a password of epzxkgjerkvgvjnw (not a real app password) and finally, the automation account cred name will be Office 365 Creds.

Note: If you have modern auth enabled in your tenant, you cannot use a app password

$AzureSplat = @{
    AutomationAccountName    = "EXOAutomationAccount";
    RunBookName              = "Office_365_EAPRunbook";
    ResourceGroup            = "rg-psautomation";
    Location                 = "North Central US";
    AutomationCredUser       = "[email protected]";
    AutomationCredPassword   = ConvertTo-SecureString "epzxkgjerkvgvjnw" -AsPlainText -Force;
    AutomationAccountCedName = "Office 365 Creds"
}

Connect-AzAccount

$RG = Get-AzResourceGroup -Name $AzureSplat.ResourceGroup -ErrorVariable notPresent -ErrorAction SilentlyContinue

if ($Null -eq $RG)
{
    #Create the Resource Group
    New-AzResourceGroup -Name $AzureSplat.ResourceGroup -Location $AzureSplat.Location
}


#Make the automation account
New-AzAutomationAccount -ResourceGroupName $AzureSplat.ResourceGroup -Location $AzureSplat.Location -Name $AzureSplat.AutomationAccountName -Plan "Free"

#Create new automation runbook
New-AzAutomationRunbook -AutomationAccountName $AzureSplat.AutomationAccountName -Name $AzureSplat.RunBookName -ResourceGroupName $AzureSplat.ResourceGroup -Type PowerShell

#Create and store automation account credentials
[System.Management.Automation.PSCredential]$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AzureSplat.AutomationCredUser, $AzureSplat.AutomationCredPassword
New-AzAutomationCredential -AutomationAccountName $AzureSplat.AutomationAccountName -Name $AzureSplat.AutomationAccountCedName -Value $cred -ResourceGroupName $AzureSplat.ResourceGroup

When I run this script the first thing it wants to do is to connect to Azure. Log in with an account with the proper permissions when prompted.

PowerShell will then start creating everything for you

And in my Resource Group blade I can see all my items

NOTE: The credentials are located within the automation account

Add Exchange Online Module to Automation Account

Next, we must allow our automation account access to the Exchange Online module so it can connect to Exchange Online. This module exposes the following cmdlets and functions:

In the Azure portal under our Automation Account, select Modules which will display all modules that our Automation Account has and select Browse Gallery

Search for ExchangeOnlineShell and then press Import

In the Import blade select OK to begin the module import

 

Azure RunBook Setup

Create the RunBook

Next, we must create our runbook that our automation account will be running. In the Azure portal under our Automation Account, select RunBooks. Here we will see our RunBook we created earlier. Click on the runbook to edit it.

Click the pencil Edit button to edit the RunBook

The PowerShell runbook has 3 default proxy formats out of the box. FirstInitialLastName, FirstName.LastName, and FirstName. You can add any other format that best fits your needs. The only information you need to modify is in the splat, the ProxyFormat and the Domain. In my example my format is FirstInitialLastName and chicagopowershell.com. So it will make sure all my mailboxes have a proxy with that format, in my case I would have a proxy of [email protected]. If I do not have one the runbook will automatically add it as an alias for me.

$ProxySplat = @{
    #Avaialble proxy format options: 'FirstInitialLastName', 'FirstName.LastName', 'FirstName'
    ProxyFormat = "FirstInitialLastName";
    Domain = "chicagopowershell.com"
}
 

[System.Management.Automation.PSCredential]$Credential = Get-AutomationPSCredential -Name "Office 365 Creds"

$Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid -Credential $Credential -Authentication Basic -AllowRedirection
 
Import-PSSession -Session $Session -DisableNameChecking:$true -AllowClobber:$true | Out-Null

Get-Mailbox -ResultSize unlimited | ForEach-Object {
    If ($ProxySplat.ProxyFormat -like "FirstInitialLastName")
    {
        $FirstInitial = ($_.DisplayName).SubString(0,1) 
        $LastName = ($_.DisplayName).Split(" ") | Select-Object -Last 1
        If ($_.EmailAddresses -like ("*[email protected]$($ProxySplat.Domain)*"))
        {
            Write-Output "$($_.DisplayName) already has an email address of [email protected]$($ProxySplat.Domain)"
        }
        Else 
        {
            Write-Output "$($_.DisplayName) does not have a email address of [email protected]$($ProxySplat.Domain)..adding..."
            Set-Mailbox -identity $_.DistinguishedName  -EmailAddresses @{add="[email protected]$($ProxySplat.Domain)"}
        }
    }
    ElseIf ($ProxySplat.ProxyFormat -like "FirstName.LastName")
    {
        $FirstName = ($_.DisplayName).Split(".") | Select-Object -First 1
        $LastName = ($_.DisplayName).Split(".") | Select-Object -Last 1
        If ($_.EmailAddresses -like ("*[email protected]$($ProxySplat.Domain)*"))
        {
            Write-Output "$($_.DisplayName) already has an email address of [email protected]$($ProxySplat.Domain)"
        }
        Else 
        {
            Write-Output "$($_.DisplayName) does not have a email address of [email protected]$($ProxySplat.Domain)..adding..."
            Set-Mailbox -identity $_.DistinguishedName  -EmailAddresses @{add="[email protected]$($ProxySplat.Domain)"}
        }
    }
    ElseIf ($ProxySplat.ProxyFormat -like "FirstName")
    {
        $FirstName = ($_.DisplayName).Split(" ") | Select-Object -First 1
        If ($_.EmailAddresses -like ("*[email protected]$($ProxySplat.Domain)*"))
        {
            Write-Output "$($_.DisplayName) already has an email address of [email protected]$($ProxySplat.Domain)"
        }
        Else
        {
            Write-Output "$($_.DisplayName) does not have a email address of [email protected]$($ProxySplat.Domain)..adding..."
            Set-Mailbox -identity $_.DistinguishedName  -EmailAddresses @{add="[email protected]$($ProxySplat.Domain)"}
        }
    }
    Else 
    {
        Write-Warning -Message "No valid proxy format detected"
    }
}

Remove-PSSession $Session

To connect to Exchange Online we can see here that its getting my automation credentials from my automation account.

[System.Management.Automation.PSCredential]$Credential = Get-AutomationPSCredential -Name "Office 365 Creds"


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

Once you have made your changes and added the PowerShell code to your runbook you can test it by selecting the Test Pane option

Testing the RunBook

In the Test Pane select Start which will queue up your runbook. Because of Write-Output, we will see verbose message for each user. In my example all of my mailboxes besides mine had the proper e-mail alias. The runbook automatically added the alias to my mailbox.

Publishing the RunBook

When you have gotten the runbook configured exactly how you like it, select Publish in the Edit blade to save and publish your runbook.

Scheduling the Runbook

For my EAP runbook I like to have it run once daily. This ensures that any users that were added that day without the correct email addresses, get the correct email address before the next business day. In the RunBook blade select Schedules

Select Add a Schedule

Create a schedule for your runbook. I set mine to run every day at 9PM.

Done! You have now created an Azure runbook that will use the automation credentials to connect to your Office 365 Exchange Online environment to ensure your exchange users have email addresses that match specific criteria that you have put in place. For more email address policies you can create more runbooks or modify this one to contain more than 1 proxy format.

3 thoughts on “Office 365 Email Address Policies with Azure Automation

  1. Great article!

    How does the FirstInitialLastName proxy format handle multiple people with which would end up with the same name?

    i.e. if you have 2 John Smiths then does the second one get josmith?

    1. good question! It should show you an error on the second user because the proxy is not unique. You could put in a IF statement that if its already exists modify it by adding a 1 or something

  2. Great article Brad.

    How do you tweak this if modern authentication is enforced on all administrative accounts?

Leave a Reply

Your email address will not be published. Required fields are marked *