none
User Profile Photo Sync in Hybrid On Prem and Office 365 RRS feed

  • General discussion

  • I thought I would share my solution to the ongoing headache of User photo synchronization as it took me forever to come across the correct information and put it all together.

    The scenario:  A hybrid on-prem environment of Sharepoint 2013 (one farm in hybrid mode, one not in hybrid mode yet, but using the 2016 Cloud Hybrid SSA as its default search application and its local User Profile  Synchronization Service/My Site Host to export the User Photo to local AD), Sharepoint 2016 in hybrid mode ( hosting our Cloud Search Service Application) and Skype for Business, utilizing Azure AD Sync to our Office 365 tenant. 

    The issue:  User Photo not synchronized between the various components above and in on premise sharepoint, showing different images or an error for the User Photo

     

    Problem one:  The dreaded gray "x" where the User Photo should be

     Most old school Sharepoint admins know and dread the error box .  The really confusing part of the problem was that when you looked at the picture properties and grabbed its URL, you could open it just find on another browser tab on its own.  And in some cases the hover panel also showed an actual user image (though not the one that was stored in the tenant!).  Let the swearing ensue.

     

    What didn't work: As many helpful resources that are out there describing this issue, most of them recommend customizing the picUrl variable in display templates in search and the content query web parts (which usually defaults to the pictureUrl mapped property or via  userProfileProperties.get_pictureUrl())  to directly reference Sharepoints built in 'proxy page" for photos in the _layouts directory called "userphoto.aspx that you call with parameters based on the account, i.e., username@domain.com.  This means concatenating a string for the picUrl variable like so:  

    https://customdomain=my.sharepoint.com/_layouts/15/userphoto.aspx?size=M&accountname=AUser@customdomain.onmicrosoft.com

    Or a site relative version, like so: /15/userphoto.aspx?size=M&accountname=AUser@customdomain.com (the above is for a 2013 farm with domain aliasing; a you would use the 16 directory for SP2016)

    <cite style="margin:0in;font-family:Calibri;font-size:9.0pt;color:#595959;"> </cite>

    I'll go more in to depth about that in the next section, but the important point is that this solution only worked if users ALREADY HAD PICTURES in the local on prem MY SITE HOST, i.e., https://my.customdomain.com/user photos/profile pictures/ and those pictures don't synch with Office 365 (even if you are writing to the thumbnailPhoto property in your local AD via the User Profile Synchronization Service; more on this in the next section).  If a user didn't have a picture uploaded via their a local my-site or profile, the default grey no photo image would display.

    And that included even the hybrid farms, so users wouldn't even know how to get to the legacy My Site profile to upload a photo in the first place.

     

    The other problem with this approach (aside from the headache of having to customize your display templates for search and content query web parts) is that still wouldn't fix lists that used a people field that displayed a photo, unless you also added some more complicated code to your master pages.

     

    Then I happened upon this article:  http://www.wictorwilen.se/sharepoint-2013-enabling-cross-domain-profile-pictures , which mentions a not very well advertised web application setting called "CrossDomainPhotosEnabled", whose default is "False":

      

    $wa = Get-SPWebApplication https://<localwebappurl>

    $wa.CrossDomainPhotosEnabled = $true

    $wa.Update()

    Once I set that, well, it "sort of" worked. On my hybrid farms, Instead of a list of x'ed out photo errors, I got the default no photo image.  An improvement, but still not doing what we need it to, as all those users had pictures in the tenant.

    After a lot of troubleshooting and inventing some really innovative profanities, it suddenly occurred to me that maybe it was trying to default to local photo cache because even though my User Profile Service was in hybrid mode, and thus redirecting to the online User Profile Service App, my original, on prem User Profile service was still running, which is the default behavior after you convert to hybrid.  Once I stopped the LOCAL user profile services (and after clearing my browser cache--don't even get me started on the false negatives I got because of the cache), the image displayed properly for all users that had uploaded their photos to the tenant (though it also depends *where* they uploaded them on the tenant. See below…).

    The behavior was slightly different In my non-hybrid farm that (temporarily) uses the Hybrid  2016 Cloud SSA for its default search application; that still was referencing the local my-site host photo storage, even with the customized display templates (I'll cover that particular solution at the end of the article as it is a somewhat less common scenario)So problem one down, no more photo errors!

     

    That battle won,  I still had a variety of different photos in different places and no one place to update them, which brings us to….

     

    Problem Two: One photo upload to unite them all!

     

    So, where is the best place to allow a user to upload their photo and have it appear across our various apps?  It's complicated….

     

    It helps to know the various vagaries of how it all "works".  There is some rather exhaustive documentation of the gordian knot that is User Photo storage and synch in Office 365 and various on prem components.  Here are some good places for detailed overviews:

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

    A more specific article detailing ALL the different places you can upload pictures to and their relationships to one another:  https://threewill.com/user-photo-sync-behavior-in-office-365/ . 

     

    Almost none of this works until  the Sharepoint Online tenant generates the Small, Medium, Large thumbnails in the User photos library on its My Site Host, and there are several caveats involved with that:

    • if you update your photo via Outlook: https://outlook.office.com/owa/?path=/options/myaccount/action/photo
      • It may take up to 72 hours to trigger the thumbnail generation
      • On prem AD's thumbnailPhoto field may or may not be included in the synch
    • If you update via Sharepoint/Delve page: https://nam.delve.office.com/<tenantuserguid>&v=editprofile
      • It may propagate to Azure AD and Outlook Web, but actually NOT persist in Sharepoint, Search etc., and not generate those oh-so-necessary thumbnails  until the user happens to visit their profile page on the tenant
    • Finally, if you update it via "My Account" on the tenant:  https://portal.office.com/account/#personalinfo
      • It updates Sharepoint Online, Azure AD, Outlook web,  and the Outlook Client (after a restart of the app)  immediately!
      • The thumbnails were generated almost immediately!  This means, barring browser caching, search results in Sharepoint also reference the correct picture! Yowza!
      • In my own Skype client, my picture also changed after I restarted Outlook!  Huzzah!
      • However, <cue sad fugle horn music> , my old picture still displayed OTHER people's Skype clients, the GAL and the on the search hover panel  and non-search based user photos in my 2013 non-hybrid environment

     

    This, after is because some of these resources pull the photo property (thumbnailPhoto) from the LOCAL side of the Active Directory  synch and (in at least our configuration) of Azure AD Sync, that field is not written back to, or if it is, that can ALSO take up to 72 hours.  In tracing picture properties, I managed to find the following page that displays what THAT photo is:

    https://account.activedirectory.windowsazure.com/r#/profile
    And of course, there is no way to change it from that UI. So how do you get local AD to pick up the same photo?

     

    There are various tools (like Hyperfish Photo Importer/Exporter) and a whole lot of complicated custom scripts online that allow for batch uploading of photos to Active Directory, but none really suited my needs or seemed too complex for what I needed to do.  Then I remembered good ole "Set-ADUser" in powershell.  You can set the photo with the -replace parameter after you encode the photo (with the limitation that the photo be less than 100k).  So, I wrote a little function to import photos as follows:

     

    function SetADPhoto {

    param ([string]$samAcctName)

    $photoStream="\\servername\import\UserPhotos\" + $samAcctName + "_customdomainname_com_LThumb.jpg"

     

    If ((Test-Path $photoStream)){

    $photo = [byte[]](Get-Content $photostream -Encoding byte)

    Set-ADUser $samAcctName -Replace @{thumbnailPhoto=$photo} -Verbose

    }#endifPhotostrea

     

    }#endSetADPhotoFunction

    And then added that to a script that queries AD for active users, retrieves their samAccountName and iterates through that list to run the function and added that to Task Scheduler.

     

    As to how to populate the same photos into the share it uses for its photo source, there are several different methods you can use.  Since we have a 100k photo size limitation, I prefer to pull from the already resized photo store in the Sharepoint Online My Site host.  You can add a function that will pull down photos from that library via powershell directly; or, you can use  the workaround I came up with to synch the online photos with my non-hybrid 2013 sharepoint farm using Microsoft Flow in the tenant.

     

    To use this solution, you need to have an On Premises Data Gateway installed in your on prem environment, an account that has read/write access to the file share and on prem My Site Host photo library if you are also synching to a non-hybrid farm:  https://www.microsoft.com/en-us/download/details.aspx?id=53127 (unless you have Azure blob with unc shares that are accessible from your on prem environment).

     

    I will give detailed instructions regarding the configuration and requirements in my next post, but here is an overview of how it works:

    • Create a Sharepoint Connection and a File System Connection on your tenant that uses the default gateway that has access to those resources
    • Build a flow for the Profile Pictures folder in User Photos on the online My Site Host using the "Sharepoint-Create file" and "File System-Create file" templates that triggers every time a file is created or modified.
      • The Sharepoint create file should point to your on prem My Site host User photo library
      • The File System create file should point to the UNC share you set up to pull photos from in the SetADPhoto script
    • Every time a user creates or modifies their photo and the thumbnails are created, they will all be copied to both of those destinations
      • Writing to the On Prem sharepoint photo store simply replaces the current image referenced by its User Profile Service with the one used online
      • Since it is the thumbnails being copied, they are already resized and fall well within the 100k AD photo limit.  I reference the _Lthumb.jpgs in my script to get the highest resolution image available in the store
        • Note:  You can also use  the User Profile Synchronization service on your on prem, non-hybrid farm to write the photo to the thumbnailPhoto property in AD instead of this step; however, we are going to be putting that farm into Hybrid Mode at some point soon, so I went with the file share based method instead

     

     

    As far as I know, there is still no way to synch photos into Yammer without accessing their API, but I hear there will soon be some crossover between User photos in  Office 365 .

    Hope this helps you avoid the flaming hoops of frustration I had to endure to get this all working!

    Stay tuned for the next related post on "How to synch photos to on premise resources via Microsoft Flow".  

     

     

    Resources:  I would not have been able to figure out this mess  if it were not for the following pages :

    Enabling Cross Domain Profile Pictures:  http://www.wictorwilen.se/sharepoint-2013-enabling-cross-domain-profile-pictures  

    GET User Image from Office 365 exchange photo store: http://www.ktskumar.com/2016/07/get-user-image-office-365/

     

    User profile picture in SP hosted app: https://mysharepointlearnings.wordpress.com/2014/02/02/user-profile-picture-in-sp-hosted-app/

     

    How to Import Employee Pictures into Active Directory: https://gallery.technet.microsoft.com/How-to-Import-Employee-0058e89b


    "I have not failed. I've just found 10,000 ways that won't work. - Thomas A. Edison"



    Monday, October 8, 2018 10:36 PM

All replies

  • Hi Vera,

    This would be useful for other community members, thanks for your kindly sharing.


    Best Regards,
    Niko Cheng


    Please remember to mark the replies as answers if they helped. If you have feedback for TechNet Subscriber Support, contact tnsf@microsoft.com.


    Click here to learn more. Visit the dedicated forum to share, explore and talk to experts about Microsoft Teams.

    Tuesday, October 9, 2018 2:27 AM
    Moderator
  • Vera, you mention in this post that you "will give detailed instructions regarding the configuration and requirements in my next post" -- do you have a link to that post?

    My scenario is not quite the same as yours, but I do need to find a solution to writeback the office online user photo back into local on-prem active directory.  We have the data gateway installed for other API needs, but am not quite following how to use that to communicate back to AD.

    Wednesday, July 17, 2019 4:50 PM