Solving ProfileBadRequestException Exceptions when updating Microsoft Graph User Profile Photo

Introduction

I had a scenario where we needed to copy user profile photos from one Microsoft Entra ID tenant to another. One of the issues that companies face is that Microsoft’s Cross Tenant Sync does not update synchronise user profile photos.

Approach

So, I built a Microsoft Azure Function that uses the Microsoft Graph SDK for .NET to connect to the source Microsoft Entra ID tenant and the target Microsoft Entra ID tenant.
The Azure Function runs through all the users in the target Entra ID and copies over the profile photo from the source Entra ID.

It seems pretty straight-forward, but of course, there was a little gotcha. It seems that my approach was failing when trying to write the photo content to the user’s profile. The exception that I was getting was this:
Microsoft.Fast.Profile.Core.Exception.ProfileBadRequestException

This exception was thrown when the following call was made:

[csharp]
await targetGraphClient.Users[user.Id].Photo.Content.PutAsync(stream);
[/csharp]

After looking around the web, I realized I was not alone. Quite a few other people were complaining about this exception and looking for solutions. Therefore, I wanted to share my approach to resolving this issue.

The first thing was to make sure we were not trying to do anything too clever and keep everything Binary.

[csharp]
System.IO.Stream sourcePhotoContent = null;
byte[] sourcePhotoBytes = null;
System.IO.MemoryStream sourcePhotoMemoryStream = new MemoryStream();

try
{
sourcePhotoContent = await sourceGraphClient.Users[sourceUser.Id].Photo.Content.GetAsync();
await sourcePhotoContent.CopyToAsync(sourcePhotoMemoryStream);
sourcePhotoMemoryStream.Position = 0;
var streamReader = new BinaryReader(sourcePhotoMemoryStream);
sourcePhotoBytes = streamReader.ReadBytes((int)sourcePhotoMemoryStream.Length);
sourcePhotoMemoryStream.Position = 0;
await targetGraphClient.Users[user.Id].Photo.Content.PutAsync(new MemoryStream(sourcePhotoBytes));
}
catch (Exception sourceImageEx)
{
}
[/csharp]

To be honest the secret was to use the Http2Stream coming from the sourcePhotoContent and copying it to the sourcePhotoMemoryStream. After that, we needed to make sure we were setting the position of the MemoryStream to 0 so that when the BinaryReader runs through the stream it reads all of the bytes and puts them into the sourcePhotoBytes byte[].

Fundamentally that is it!

Oh one last thing, permissions! Mke sure you have the right Microsoft Graph Permissions assigned to the Microsoft Entra ID application that you are using. The permissions that I used were the following:

  • User.ReadBasic.All
  • ProfilePhoto.ReadWrite.All

Conclusion

This was a short post. I hope you found it useful if you are trying to do something similar using the Microsoft Graph SDK and hitting the same “Microsoft.Fast.Profile.Core.Exception.ProfileBadRequestException” exception.

If you used this, let us know you got on.

Thoughts? Comments about this post? Please leave them here..

This site uses Akismet to reduce spam. Learn how your comment data is processed.