Office 365: Stale Information in the Offline Address Book and Individual Contact Cards

In Office 365 an Exchange related object can be replicated from the on premises Active Directory to Azure Active Directory and then forward synchronized into the Exchange Online Active Directory.  In most cases the objects synchronized into the Exchange Online Active Directory represent mail enabled objects.  User accounts are unique in that they are replicated into Exchange Online regardless of their mail enabled status.  The user accounts residing in the Exchange Online Active Directory can be seen with the get-user command.

Let us take a look at an example.  An on premises a remote mailbox object is created –> Direct Report. When running get-user against the on-premises account a MAILUSER is returned.  This is expected for a remote mailbox.

[PS] C:\>Get-User DirectReport

Name RecipientType

---- -------------

Direct Report MailUser

An on premises account is created –> Team Manager.  Team Manager is not a mail enabled object.  When running get-user against the on-premises account a USER object is returned.  This is expected for a user object that is not mail enabled.

[PS] C:\>Get-User TeamManager

Name RecipientType

---- -------------

Team Manager User

In this particular instance DIRECTREPORT has been assigned the MANAGER TEAM MANAGER.

[PS] C:\>Get-User DirectReport | fl name,manager

Name : Direct Report

Manager : domain.local/Users/Team Manager

Using get-user in Office 365 for the remote mailbox we can see that it is listed as a USERMAILBOX.  This is expected for a remote mailbox object.

PS C:\> Get-User DIRECTREPORT

Name RecipientType

---- -------------

Direct Report UserMailbox

The TEAMMANAGER account remains as a USER object in Exchange Online.

PS C:\> get-user "Team Manager"

Name RecipientType

---- -------------

Team Manager User

As previously highlighted the objects represented in Exchange Online Active Directory also have a representation in Azure Active Directory.  The link between the objects can be seen on the user objects ExternalDirectoryObjectID. 

PS C:\> Get-User "Team Manager" | fl externalDirectoryObjectID

ExternalDirectoryObjectId : b3343293-8837-492b-88e6-08c4c4ec5099

Using the external directory object ID the get-MSOLUser command can be utilized to find a corresponding object. 

PS C:\> Get-MsolUser -ObjectId b3343293-8837-492b-88e6-08c4c4ec5099

UserPrincipalName DisplayName isLicensed

----------------- ----------- ----------

teammanager@domain.org Team Manager False

The end conclusion is that a valid user object in Exchange Online Active Directory is also represented by a valid object in Azure Active Directory (and potentially on-premises Active Directory if sourced on premises).

The Offline Address Book and individual contact cards displaying information like manager and direct reports.  These types of settings are not limited to recipients – but also include user objects as in this scenario.  Pulling the contact card for a manager shows the direct reports and pulling a direct report shows the manager.  This information is based from the user settings exposed through get-user.

I recently worked on an escalation where some users individual contact cards were not correct.  Some users were showing direct reports that no longer existed in the company and the same with manager attributes.  How did we determine the users were not available?

To begin the investigation we started by narrowing down where the direct report could be seen within the clients.    In this case a manager was reporting that a direct report that left the company was still showing on the users contact card.  The direct report – Bill James (bjames@domain.com) was confirmed be on the contact card in Outlook Web Access, Outlook Online Mode, and Outlook Cached Mode.  What this tells us is that this is not an issue with the build of the Offline Address Book – as online mode clients always display information directly from the directory.

Azure AD Connect is utilized in the environment to synchronize objects from the on premises Active Directory to Azure Active Directory.  Since the source of objects was on premises we verified that the account could not be found. 

[PS] C:\>get-user bjames@domain.com

The operation couldn't be performed because object 'bjames@domain.com' couldn't be found on 'Azure-Dc.fmrs.local'.
+ CategoryInfo : NotSpecified: (:) [Get-User], ManagementObjectNotFoundException
+ FullyQualifiedErrorId : [Server=AZURE-MBX,RequestId=25a34a91-9c7f-46df-a40e-399809d5e318,TimeStamp=9/10/2018 3:4
4:58 PM] [FailureCategory=Cmdlet-ManagementObjectNotFoundException] 6BDE9D0,Microsoft.Exchange.Management.Recipien
tTasks.GetUser
+ PSComputerName : azure-mbx.domain.local

This output validated that the object was not found in the on-premises Active Directory.

The next phase of the investigation was to determine if the object resided in Azure Active Directory.  Is it possible that a delete from on-premises was not processed into the directory that is the source of information for other workloads.

PS C:\> Get-MsolUser -SearchString bjames

PS C:\>

In this particular instance nothing was returned.  For good measure we also looked at deleted objects.

PS C:\> Get-MsolUser -SearchString bjames -ReturnDeletedUsers

PS C:\>

This confims that the user account is not present in Azure Active Directory.

The last step of the investigation is to review the Exchange Online Active Directory. 

PS C:\> get-user "Bill James"

Name RecipientType
---- -------------
Bill James User

In this particular instance a user object is found in Exchange Online.  When reviewing the recipient type we can see that the recipient is of class USER.  If the recipient does not exist on premises and does not exist in Azure Active Directory then why does it exist in Exchange Online Active Directory.  Does the object have an external directory object ID? 

PS C:\> Get-User "Bill James" | fl externalDirectoryObjectID

ExternalDirectoryObjectId : b1583093-3345-324a-7ae6-09b45e6a1b33

In this example the user does have an external directory object ID.  This means we should be able to locate the object in Azure Active Directory.

PS C:\> Get-MsolUser -ObjectId b1583093-3345-324a-7ae6-09b45e6a1b33

Get-MsolUser : User Not Found. User: b1583093-3345-324a-7ae6-09b45e6a1b33.

At line:1 char:1

+ Get-MsolUser -ObjectId b1583093-3345-324a-7ae6-09b45e6a1b33

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [Get-MsolUser], MicrosoftOnlineException
+ FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.UserNotFoundException,Microsoft.Online.Admini
stration.Automation.GetUser

The user object still cannot be found in Azure Active Directory.

In this particular example the Exchange Online Active Directory account was orphaned. The account was removed from Azure Active Directory but the account still exists in the Exchange Online Active Directory which results in the associated contact card displays.

How does one resolve this particular issue.  To resolve this issue a support case needs to be opened with Office 365 support.  There can be several reasons that an account is orphaned that does not pertain to missing a deletion notification – and support can work with customers to identify these causes or escalate to our product engineering groups.

If you’re interested in identifying potentially orphaned accounts in bulk – we can utilize the following procedure.

  • Gather all objects of TYPE user and export the userprincipalName and externalDirectoryObjectID (if not NULL).
    • $users=invoke-command {Get-User -ResultSize unlimited | where {$_.externalDirectoryObjectID -ne $NULL} | select-object userPrincipalName,ExternalDirectoryObjectID}
    • $users | export-CSV –path c:\Temp\UsersWithExternalDirectoryObjectID.csv
  • Scan all user objects for errors locating an external directory object ID in Azure Active Directory.
    • $users | % { $error.clear() ; get-msolUser –objectID $_.externalDirectoryObjectID ; if ( $error –ne $NULL ) { $row = new-object psobject ; $row | add-member –memberType NoteProperty –value $_.externalDirectoryObjectID –name “Name” $data += $row }}
    • $data | export-csv –path c:\temp\PotentiallyOrphanedUsers.csv
  • Scan all objects not found in Azure Active Directory to determine deleted status.  If deleted user is not orphaned.  If not found user if orphaned.
    • $users | import-csv c:\temp\PotentiallyOrphanedUsers.csv.
    • $users | % { $error.clear() ; get-msolUser –objectID $_.externalDirectoryObjectID –returnDeletedUsers; if ( $error –ne $NULL ) { $row = new-object psobject ; $row | add-member –memberType NoteProperty –value $_.externalDirectoryObjectID –name “Name” $data += $row }}
    • $data | export-csv –path c:\temp\OrphanedUsers.csv

This data can be provided to Office 365 support to assist in reconciliation and remediation.