The on-premises Active Directory attribute thumbnailPhoto can store the users photo. This photo can then be used by applications like Outlook, Skype for Business and SharePoint. Exchange/Outlook and Skype for Business both will use by default the thumbnailPhoto attribute to display the users photo.

The maximum size in on-premise Active Directory and Azure AD for the thumbnailPhoto attribute is 100 kB and the recommended size is 96 x 96 px. For the file type you can use JPEG and PNG.




Introduction

Exchange on-premise and Exchange online will by default import the thumbnailPhoto to show the photo in Outlook and Outlook on the web if it not exceed the limit of 10 KB.

Further the thumbnailPhoto attribute is synced only one time between Azure AD and Exchange Online. Any later changes/updates to the attribute from the on-premises environment are not synced to Exchange Online.
Source: https://docs.microsoft.com/en-us/exchange/troubleshoot/administration/user-photos-not-synced-to-exchange-online

In contrast the thumbnailPhoto attribute is synced continuously between on-premise and Azure AD. Nevertheless I also here encountered sometimes problems, that the photo is not really shown up with the updated version in the Azure Portal under the Azure Active Directory – All users panel, even it is still shown up updated in the Microsoft 365 Portal at the right top besides the username for the signed-in user. In this case to force the update also for the Azure Active Directory – All users panel, you can update the photo using the below Set-UserPhoto cmdlet for Exchange Online, which will also update the photo in Azure AD, provided the mailbox of the user is still in Exchange Online.

To update the user photo in Exchange Online you can use the Set-UserPhoto cmdlet or Outlook on the web to change the user’s photo. These methods also enable you to upload a photo that’s as large as 500 KB. If importing directly into Exchange, the photo will also be synced back to Azure AD.

for example:
# Connect to Exchange Online
Import-Module ExchangeOnlineManagement
$credential = Get-Credential
Connect-ExchangeOnline -Credential $credential -ShowProgress $true

# Change or set the User Photo in Exchange Online
Set-UserPhoto -Identity “John Doe” -PictureData ([System.IO.File]::ReadAllBytes(“C:\Users\Administrator\Desktop\JohnDoe.jpg”))

# Remove User Photo in Exchange Online
Remove-UserPhoto “John Doe”



To update the thumbnailPhoto in your on-premise Active Directory you can use one of the following cmdlets

Using the Active Directory Module for Windows PowerShell
The picture must be a JPEG or PNG file and shouldn’t be larger than 100 kilobytes (KB)

Set-ADUser jdoe -Replace @{thumbnailPhoto=([byte[]](Get-Content “D:\ADPics\john_doe.png” -Encoding byte))}

Source: https://docs.microsoft.com/en-us/powershell/module/activedirectory/set-aduser


Using the Exchange Management Shell
The picture must be a JPEG file and shouldn’t be larger than 10 kilobytes (KB)

Import-RecipientDataProperty -Identity “John Doe” -Picture -FileData ([Byte[]]$(Get-Content -Path “D:\ADPics\john_doe.png” -Encoding Byte -ReadCount 0))

Source: https://docs.microsoft.com/en-us/powershell/module/exchange/import-recipientdataproperty


To update the thumbnailPhoto in an cloud only Azure AD Environment where you do not sync your on-premise network to Azure AD, you can use the following cmdlet.

# first login into Azure AD
$credential = Get-Credential
Connect-AzureAD -Credential $credential

Set-AzureADUserThumbnailPhoto -ObjectId <User ObjectID> -FilePath <File Path to you photo>

$user = Get-AzureADUser -SearchString jdoe@braintesting.de
Set-AzureADUserThumbnailPhoto -ObjectId $user.ObjectId -FilePath “D:\ADPics\john_doe.png”

Source: https://docs.microsoft.com/en-us/powershell/module/azuread/set-azureaduserthumbnailphoto



But now after this short introduction about the thumbnailPhoto attribute, let’s come to the error stated in the title of this post.

If I had known the fact,

that the thumbnailPhoto attribute is synced only one time between Azure AD and Exchange Online. Any later changes to the attribute from the on-premises environment are not synced to Exchange Online.

than I wouldn’t have run into that error in the first place!

In my case I determined, that if a users thumbnailPhoto attribute was updated in on-premise and synced successfully to Azure AD, nevertheless wasn’t updated in Exchange Online.


Update for this post from 10-28-2021 !!!!
At this point I had described recently how I ran into that error with a detailed description what I had mistakenly configured. While I extra mentioned not to do this in your own environment, as it was only to point out what configuration steps can lead to such an error, some readers of this post apparently and according to a Microsoft escalation engineer, misunderstood it as solution and configured these steps in their own environment and then of course also runs into that error. Therefore that engineer from Microsoft asked me to remove that steps to prevent other readers from also mistakenly configuring that steps and finally not also hit at the MS Support.

If you ask me, to prevent user’s from running into that error in the first place and not hit at the MS Support, Microsoft should better adjust that process to also sync the thumbnailPhoto attribute continuously from Azure AD to Exchange Online, despite of the increased replication traffic or what ever reason they keep from doing so, instead of asking for to adjust posts to be foolproof and not showing what can lead to that error.

Anyway, therefore these steps from now on missing here but you will of course still see how to solve that issue below.

As in these steps many details about the error itself was described, I have outsourced them into a separate post with admit of no doubt to not reproduce this and that it is only for understanding purpose why and how that error exactly appeared.

You will find this post here
https://blog.matrixpost.net/appendix-azure-ad-connect-sync-errors-detected-large-attribute-extension-thumbnailphoto/


Therefore in short why I ran into that error.

Falsely I configured the thumbnailPhoto (user) [Binary] attribute in the Azure AD Connect directory extensions section and promptly ran into that large attribute error, so again, don’t do this in your environment!!!


But how can you get rid of this error?


The solution is to create a new sync rule, using the Synchronization Rules Editor which is installed along with Azure AD Connect, which will set the value of the new extension attribute to NULL and therefore empty in Azure AD.

Do not flow an attribute (Create a rule to set attribute to null in Azure AD)
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sync-change-the-configuration#do-not-flow-an-attribute

For background on the scenario for this section, see Control the attribute flow process.

There are two ways to not flow an attribute. The first is by using the installation wizard to remove selected attributes. This option works if you have never synchronized the attribute before. However, if you have started to synchronize this attribute and later remove it with this feature, the sync engine stops managing the attribute and the existing values are left in Azure AD.

If you want to remove the value of an attribute and make sure it does not flow in the future, you need create a custom rule.


As I still synchronized the extension attribute to Azure AD, I cannot simply remove the whole extension attribute from the Azure AD schema, as far as I know anyway and regarding the above article about not to flow the attribute. Therefore I need to create a sync rule, which will at least remove the value for this attribute in Azure AD and set it to NULL, therefore empty.

This will remove the extension property from the directory object user, not from the schema.

As mentioned, removing the whole extension attribute from the schema created through Azure AD Connect directory extensions, isn’t possible as far as I know.

At least I can’t find any resource in the web, where it is described how to get rid of a directory extension attribute in the schema created by Azure AD Connect.


The available PowerShell cmdlet and Microsoft Graph API below works, if you created an extension using the New-AzureADApplicationExtensionProperty cmdlet, where you can create an extension property associated to a specific app.

At the end I will show an example, about how to create an application extension property under Appendix – Create an application extension property.


When using Azure AD Connect with the directory extensions, the extensions will be associated by default to the Tenant Schema Extension App. This App will be only created if you select in Azure AD Connect a directory extension and during the first synchronization of an extension attribute.

Directory schema extension attributes are always associated with an application in the tenant and are referenced by the application’s applicationId in their name.

The identifier for a directory schema extension attribute is of the form Extension_xxxxxxxxx_AttributeName. Where xxxxxxxxx is the applicationId of the application the extension was defined for.

Directory schema extension attributes can be registered and populated in one of two ways:
– By configuring AD Connect to create them and to sync data into them from on premises AD. See Azure AD Connect Sync Directory Extensions.
– By using Microsoft Graph to register, set the values of, and read from schema extensionsPowerShell cmdlets are also available.

Source: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-schema-extensions

More about that you will find in the following article from Microsoft.

Azure AD Connect sync: Directory extensions
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sync-feature-directory-extensions


But now let’s come back to get rid of the nasty sync errors. Therefore open the Synchronization Rule Editor to add our new Sync Rule to set the value of the extension attribute to NULL in Azure AD.

You can skip the Scoping filter and Join rules section above.

In the Transformations section we need to create an attribute flow with Expression for FlowType and with AuthoritativeNull for Source. The literal AuthoritativeNull indicates that the value should be empty in the metaverse, even if a lower-precedence sync rule tries to populate the value.

Metaverse is one of the data storage types the sync engine from Azure AD Connect uses. More about that you will find im my following post https://blog.matrixpost.net/azure-ad-connect-sync-architecture-simplified/

An extension property value must be explicitly set to null in order to be removed from a directory object. 

Source: https://docs.microsoft.com/en-us/previous-versions/azure/ad/graph/howto/azure-ad-graph-api-directory-schema-extensions#extension-behavior-and-limitations–


Save the sync rule. Start the Synchronization Service, find the connector, select Run, and then select Full Synchronization. This step recalculates all attribute flows.

Verify that the intended changes are about to be exported by searching the Connector Space.


Here you can see the Connector Space for the user object Joe Average. You can see that our extension attribute extension_d925dac931f54e76b9992b75abc3b9a6_thumbnailPhoto value now will be deleted.


I can also check with the following PowerShell cmdlet as done previously if the value from the extension attribute is really removed.

# Using the Azure AD PowerShell cmdlet
$UserId = (Get-AzureADUser -SearchString ).ObjectId
Get-AzureADUser -ObjectId $UserId | Select -ExpandProperty ExtensionProperty

Looks fine!

In contrast before executing the new sync rule.

Also the sync errors are gone and looks fine now!


Unfortunately as mentioned, the extension attribute itself is not removed from the Azure AD schema, only the value will not be synced anymore and if present in Azure AD, it will be removed. Therefore the extension property is removed from the user object but not from the schema itself.

If you run the following commands, you can check the existing extension attributes in your Azure AD schema. Below you will see that I also created a few more extension attributes with Azure AD Connect using the directory extensions. They don’t really make sense and only for testing purpose about handling extension attributes.

You will further see if the attribute is synced from on-premise or not, true means that you have selected this extension attribute in Azure AD Connect under directory extensions. But in our case with the new sync rule and AuthoritativeNull for the source, will result in the metaverse with an empty value and therefore the value in Azure AD also will be removed.


Get-AzureADApplication | Get-AzureADApplicationExtensionProperty
Get-AzureADExtensionProperty | fl -Force -Property *

extension_d925dac931f54e76b9992b75abc3b9a6_thumbnailPhoto

List all extension attributes which are associated to a specific app
Get-AzureADApplicationExtensionProperty -ObjectId <applicationObjectId>

Get-AzureADExtensionProperty
Get-AzureADExtensionProperty -IsSyncedFromOnPremises $True

The Get-AzureADExtensionProperty cmdlet gets a collection that contains the extension properties registered with Azure Active Directory (Azure AD) through Azure AD Connect. You can get extension properties that are synced with on-premises Azure AD, those that are not synced with on-premises Azure AD, or both types.

Source: https://docs.microsoft.com/en-us/powershell/module/azuread/get-azureadextensionproperty


We can also check the existing directory extension using Microsoft Graph as follows:

https://developer.microsoft.com/en-us/graph/graph-explorer

GET https://graph.microsoft.com/v1.0/applications/<applicationObjectId>/extensionProperties

The applicationObjectId you can determine using PowerShell or the Azure Portal.

Get-AzureADApplication | Where-Object {$_.DisplayName -Like ‘Tenant*’}

or the Microsoft Graph

Request all applications
GET https://graph.microsoft.com/v1.0/applications

Request a specific application and its extension attributes using the applicationObjectId
GET https://graph.microsoft.com/v1.0/applications/721d7087-a525-4739-8dca-fd881ef96971/extensionProperties

Use query parameters to customize responses
https://docs.microsoft.com/en-us/graph/query-parameters


If using the Azure Portal to determine the applicationObjectId, you have to look under Azure Active Directory – App registrations and not Enterprise applications, which will only show the object id from the service principal of the Tenant Schema Extension App.

More about the differences between App registrations and Enterprise applications, you will find in my following post https://blog.matrixpost.net/azure-ad-app-registrations-vs-enterprise-applications/


Get-AzureADApplication | Where-Object {$_.DisplayName -Like ‘Tenant*’}


App registrations


Microsoft Graph
https://developer.microsoft.com/en-us/graph/graph-explorer

GET https://graph.microsoft.com/v1.0/applications/<applicationObjectId>/extensionProperties


Directory schema extensions | Graph API concepts
https://docs.microsoft.com/en-us/previous-versions/azure/ad/graph/howto/azure-ad-graph-api-directory-schema-extensions#ViewRegisteredExtensions


You can also directly request only one extension by using the following URI with the extensionObjectId

https://graph.microsoft.com/v1.0/applications/<applicationObjectId>/extensionProperties/<extensionObjectId>

https://graph.microsoft.com/v1.0/applications/721d7087-a525-4739-8dca-fd881ef96971/extensionProperties/b857bc82-400c-45cf-8427-856ac05c6ec9


Checking the on-premise attributes properties

For on-premises you can use the Active Directory schema snap-in console to manage the schema.

To make the Active Directory Schema mmc snap-in available you first have to register the schmmgmt.dll. Therefore run the following command:

regsvr32 schmmgmt.dll


Here you can see btw. that the thumbnailPhoto attribute from on-premise had an maximum limit of 100 KB.

102400 Bytes -> 100 KB max size for thumbnailPhoto attribute




Appendix – Sync Rule

The scheduler runs every 30 minutes by default. Make sure it is not starting while you are making changes and troubleshooting your new rules. To temporarily disable the scheduler, start PowerShell and run

Set-ADSyncScheduler -SyncCycleEnabled $false.


Sync Rule – Precedence

When multiple inbound sync rules are configured to contribute to the same metaverse attribute, then precedence is used to determine the winner. The sync rule with highest precedence (lowest numeric value) is going to contribute the value. The same happens for outbound rules. The sync rule with highest precedence wins and contribute the value to the connected directory.

Source: https://docs.microsoft.com/en-us/azure/active-directory/hybrid/concept-azure-ad-connect-sync-declarative-provisioning#control-the-attribute-flow-process


Sync Rule – Special Literals

In some cases, rather than contribute a value, the sync rule should determine how other rules should behave. There are some special literals used for this case.

For inbound Synchronization Rules, the literal NULL can be used to indicate that the flow has no value to contribute. Another rule with lower precedence can contribute a value. If no rule contributed a value, then the metaverse attribute is removed. For an outbound rule, if NULL is the final value after all sync rules have been processed, then the value is removed in the connected directory.

The literal AuthoritativeNull is similar to NULL but with the difference that no lower precedence rules can contribute a value.

An attribute flow can also use IgnoreThisFlow. It is similar to NULL in the sense that it indicates there is nothing to contribute. The difference is that it does not remove an already existing value in the target. It is like the attribute flow has never been there.

Source: https://docs.microsoft.com/en-us/azure/active-directory/hybrid/concept-azure-ad-connect-sync-declarative-provisioning#control-the-attribute-flow-process


Schema Extensions available in Azure AD

Microsoft Graph offers two types of extensions. Choose the extension type that best suits your application needs:

  • Open extensions: A good way for developers to get started.
  • Schema extensions: A more versatile mechanism for developers who care about storing typed data, making their schema discoverable and shareable, being able to filter, and in the future, being able to perform input data validation and authorization.


Azure AD directory schema extensions

Azure AD supports a similar type of extension, known as directory schema extensions, on a few directoryObject resources. You can use the Microsoft Graph API to manage the extension property definitions and add, get, update and delete data in the properties of these extensions.

Source: https://docs.microsoft.com/en-us/graph/extensibility-overview#schema-extensions?WT.mc_id=AZ-MVP-5000174


Extension attributes for Azure Active Directory
https://docs.microsoft.com/en-us/answers/questions/171019/extension-attributes-for-azure-active-directory.html

Create schema extensions with:

AD Connect Schema Extensions
Microsoft Graph Schema Extensions
Microsoft Graph Open Extensions

AD Connect extensions come in the form as described above extension_(ApplicationID)_(AttributeName) and are listed as attributes in the top level of the User resource just like all the other attributes.

MS Graph schema extensions lead to a nested schema on the User resource and have a schema ID in the form similar to (appdomain)_(schemaName). This schema has attributes including a nested “properties” collection which describes the typed extension attributes in the schema.



Appendix – Create and Remove an application extension property.

As mentioned further above, the available PowerShell cmdlet and Microsoft Graph API to delete an extension attribute from the schema, doesn’t work for directory extensions created with Azure AD Connect, as far as I know and also doesn’t find any resource on the web about how to.

If you created an extension using the New-AzureADApplicationExtensionProperty cmdlet, where you can create an extension property associated to a specific app, you can use them to delete.

Below I will show an example how to create an application extension property and how to delete them.

# determine the Object ID from your Application you want to associate a new extension property
Get-AzureADApplication | Where-Object {$_.DisplayName -Like 'WebApplication14*'}

# create the new application extension property
New-AzureADApplicationExtensionProperty -ObjectId "3d2d46d6-dba2-44bc-839b-0a538434057c" -DataType "string" -Name "mra_test_extension_attribute01" -TargetObjects User

# set a value for the extension property and assign it to an user
$user = Get-AzureADUser -SearchString jdoe@braintesting.de
Set-AzureADUserExtension -ObjectId $user.ObjectId -ExtensionName extension_8c41826abc0247348f696c6b83c16c16_mra_test_extension_attribute01 -ExtensionValue "John Doe Test Extension 01"

# list all extension properties for your user
Get-AzureADUserExtension -ObjectId $user.ObjectId

# OR

Get-AzureADUser -ObjectId $user.ObjectId | Select -ExpandProperty ExtensionProperty


# list all associcated extensions properties from all applications in your tenant
Get-AzureADApplication | Get-AzureADApplicationExtensionProperty

# remove an associated extension property
$app = Get-AzureADApplication | Where-Object {$_.DisplayName -Like 'WebApplication14*'}
Remove-AzureADApplicationExtensionProperty -ObjectId $app.ObjectId -ExtensionPropertyId ed2dce1b-e7fc-4ad7-954d-c15c97cec84a


Here you can see that I could delete the extension property, even it was assigned before with an value to the user John Doe.

And here you can see the extension property with an value assigned for the user John Doe before deleting it above.


Remove-AzureADApplicationExtensionProperty
Source: https://docs.microsoft.com/en-us/powershell/module/azuread/remove-azureadapplicationextensionproperty

Directory schema extensions | Graph API concepts
https://docs.microsoft.com/en-us/previous-versions/azure/ad/graph/howto/azure-ad-graph-api-directory-schema-extensions

Unregister an extension
https://docs.microsoft.com/en-us/previous-versions/azure/ad/graph/howto/azure-ad-graph-api-directory-schema-extensions#UnregisterAnExtension

DELETE https://graph.microsoft.com/v1.0/applications/<applicationObjectId>/extensionProperties/<extensionObjectId>



Links

Do not flow an attribute
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sync-change-the-configuration#do-not-flow-an-attribute

Control the attribute flow process
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/concept-azure-ad-connect-sync-declarative-provisioning#control-the-attribute-flow-process

Azure AD Connect sync: Understanding Declarative Provisioning
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/concept-azure-ad-connect-sync-declarative-provisioning

Azure AD app and attribute filtering
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-install-custom#azure-ad-app-and-attribute-filtering

Custom installation of Azure Active Directory Connect
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-install-custom

Azure AD Connect sync: Directory extensions
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sync-feature-directory-extensions
https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/active-directory/hybrid/how-to-connect-sync-feature-directory-extensions.md

Refresh directory schema in Azure AD Connect
https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/active-directory/hybrid/how-to-connect-sync-feature-directory-extensions.md

Directory schema extensions | Graph API concepts
https://docs.microsoft.com/en-us/previous-versions/azure/ad/graph/howto/azure-ad-graph-api-directory-schema-extensions#ViewRegisteredExtensions

Azure AD cmdlets for working with extension attributes
https://github.com/Azure/azure-docs-powershell-azuread/blob/master/docs-conceptual/azureadps-2.0/using-extension-attributes-sample.md

Information about profile picture synchronization in Microsoft 365

https://support.microsoft.com/en-us/office/information-about-profile-picture-synchronization-in-microsoft-365-20594d76-d054-4af4-a660-401133e3d48a