Raymond Tishenko

Raymond Tishenko

Thoughts, ideas and general ramblings of a SharePoint and Infrastructure Consultant in Vancouver, BC

I'm addicted to coffee. There, I said it.



Sync Mobile Phone properties from Azure Active Directory to SharePoint Online User Profiles with Azure Automation Runbooks

Sync mobilePhone from Azure AD to CellPhone in SharePoint Online User Profiles using Azure Automation Runbooks and a PnP PowerShell Script

Wow, long title for a post that's long overdue! I'd written about a solution to this same challenge previously, utilizing a scheduled task running from an on-premises server. The script didn't age terribly well and required a few updates, which I didn't take care of but rather let it languish. To those that reached out to me regarding this I appreciate the feedback, and this is my attempt at an updated, simpler and more robust solution to the same challenge.

The Challenge

The User Profile Sync in SharePoint Online imports a number of properties from Azure Active Directory - but we're unable to configure any additional property mappings for import. This creates a challenge where the mobilePhone Active Directory attribute does not get synchronized to the SharePoint Online User Profile CellPhone property, despite what the Azure AD Connect sync: Attributes synchronized to Azure Active Directory may lead you to believe.

A Solution

To solve this we'll take an approach that involves an Azure Automation Runbook, the MSOnline and PnP PowerShell Online cmdlets to update the SharePoint User Profiles using the Azure Active Directory data.

We'll use the PowerShell and Automation Account approach as it's generally more familiar to the IT Pros, and the support for PowerShell is still experimental in Azure Functions. However, if you'd prefer to take that approach it's equally valid but requires a little more familiarity with coding - there are examples of this online.

Additionally, since Azure Automation supports the secure use of variable and credential storage we'll gain the benefit of not having hard-coded scripts containing usernames and passwords.


To accomplish this we'll need to have the following:

Configuring the Azure Automation account and Runbook

Create the Automation Account

Log into the Azure Portal and create a new Automation Account:

Add Automation Account resource

For our purposes we don't need the 'Run As Account':

Create Automation Account

Import PowerShell Modules

Once the Automation Account is created we need to import the PowerShell Modules into the Automation Account for use by the PowerShell scripts. Open the Automation Account and click on the Modules link in the Shared Resources section:

Automation Account Modules

Click the Browse gallery link:

Browse Module gallery

and then search for MSOnline:

MSOnline Module in the Gallery

Click into the module, then on the Import link:

Import MSOnline module

Click the OK button and then wait for the module to successfully import:

MSOnline module imported

Repeat the above for the SharePointPnPPowerShellOnline module:

SharePointPnPPowerShell Online Module in the Gallery

Confirm that both modules are imported by reviewing the available modules:

Modules List

Automation Account Variables and Credentials

To enable some flexibility in the script we'll utilize a few Automation Account Variables and Credentials - in fact, we'll create a variable for the credential name in case this already exists in the environment.

Create the Automation Account Credential first so we can refer to it by name in a variable. The credentials should be named o365GlobalAdmin and look something like the following:

Office 365 Global Administrator Credentials
If your Office 365 Global Administrator account is MFA-enabled you'll need to have and use an App Password

The script relies on the following variables:

Create the first variable o365GlobalAdminCredentialName which contains the name of the Azure Automation Credential created above (o365GlobalAdmin), as a non-encrypted string type variable similar to the following:

Credential Variable

The second variable overwriteExistingSPOUPAValue is a boolean (True/False) type that indicates whether or not we'll overwrite existing values in the SharePoint Online User Profile store. When set to True the script will use the values in Azure AD as the source of truth which may overwrite any values that users have updated in their profiles manually:

Overwrite UPA Property Values Variable

The last variable tenantName is a string type and contains the Company name portion of the Office 365/Azure AD Tenant:

Office 365 Tenant Name Variable
The script uses the tenantName variable to build the Url to the SharePoint Online Administration site, for example https://YOURTENANTNAMEHERE-admin.sharepoint.com/

That's all we need to setup the Automation Account for use by the Runbook.


At this point we need to create the Runbook which will contain our PowerShell script, click on the Create a runbook link:

Create a runbook

Give the runbook a name, select PowerShell as the type and optionally set a description - click the Create button once everything looks good:

Once created, click the Edit button:

This will open the browser-based code editor, into which we'll upload the PowerShell script:

Import-Module MSOnline
Import-Module SharePointPnPPowerShellOnline

# Automation Variables
$tenantName = Get-AutomationVariable -Name "tenantName"
$spoAdminUrl = "https://$tenantName-admin.sharepoint.com"
$overwriteExistingSPOUPAValue = Get-AutomationVariable -Name "overwriteExistingSPOUPAValue"

# Get credentials from Automation Variables
$credential = Get-AutomationPSCredential -Name (Get-AutomationVariable -Name "o365GlobalAdminCredentialName")

Try {
    # Connect to AzureAD
    Connect-MsolService -Credential $credential

    # Connect to SPO using PnP
    $spoPnPConnection = Connect-PnPOnline -Url $spoAdminUrl -Credentials $credential -ReturnConnection

    # Get all AzureAD Users with a populated MobilePhone property
    $AzureADUsers = Get-MsolUser -All | Where-Object {(![string]::IsNullOrWhiteSpace($_.MobilePhone))}

    ForEach ($AzureADUser in $AzureADUsers) {
        # Check to see if SPO UserProfileProperty CellPhone differs from AzureAD User Property MobilePhone
        if((Get-PnPUserProfileProperty -Account $AzureADUser.UserPrincipalName).UserProfileProperties.CellPhone -ne $AzureADUser.MobilePhone){
            # Property differs, update with AzureAD value
            # Check to see if we're to overwrite existing property value
            if ($overwriteExistingSPOUPAValue -eq "True") {
                Write-Output "Update CellPhone for $($AzureADUser.UserPrincipalName)"
                Set-PnPUserProfileProperty -Account $AzureADUser.UserPrincipalName -PropertyName CellPhone -Value $AzureADUser.MobilePhone
                # Not going to overwrite existing property value
                Write-Output "Target SPO UPA CellPhone is not empty for $($AzureADUser.UserPrincipalName) and we're to preserve existing properties"
Catch {
    $exception = $_.Exception.Message
    Write-Output "$($exception)"

Click the Publish button in the Edit window and we're ready to give the script a quick test.

Back on the Runbook Overview screen click the Start link and wait a few minutes - the script will run and output any messages, Warnings or Errors as it executes.

Here's a screenshot of the Output tab showing that there are users with different values in the mobilePhone / CellPhone properties, but since overwriteExistingSPOUPAValue is currently set to False the target values will be preserved:

Output tab showing target properties will be preserved

At this point we can modify the overwriteExistingSPOUPAValue variable to True, and set the runbook to run on a schedule by clicking Schedules and Add a schedule:

Add a schedule to the runbook

Click through the Link a schedule to your runbook and Create a new schedule. The following example shows a daily recurring schedule with no end date:

Create new daily schedule

Confirm that the Runbook is schedule to execute on the schedule:

Runbook scheduled to run daily

At this point the configuration is complete and scheduled to execute daily.


Following the scheduled execution, we can see that the Azure Active Directory Users that had a value in the mobilePhone attribute now have the same value in the SharePoint User Profile property CellPhone. In my test tenant we'll take a look at Binaca Pisani's account information:

BiancaP Azure AD User Mobile Phone

And we can compare that to the SharePoint User Profile property of CellPhone:

SharePoint User Property CellPhone

Note that even though the value exists in the User Profile Property Store we need to wait for Search to crawl the update before it'll show in our search-based Employee Directories. Here we can see the property exists in the Delve profile card as well:

Delve profile card


Currently the mobilePhone values from Azure Active Directory don't sync to the SharePoint Online User Profile Store - we're unable to modify the configuration of the import to make this happen.

We've worked-around the challenge with an automated approach - using Azure Automation Runbooks, PnPPowershell and a simple script that identifies users having a mobilePhone value in Azure Active Directory and sets the same value in the SharePoint User Profile CellPhone property.

I hope this helps!

Let me know what you think of this approach and I'll try to be more responsive than the three-year cycle my last post was treated to.

I'm addicted to coffee. There, I said it.

View Comments