cancel
Showing results for 
Search instead for 
Did you mean: 

Sync Profile pictures from Azure AD

ctaveras
Newcomer
Newcomer

I am trying to Sync Azure AD Profile pictures for all users to Zoom

I am trying to find info on this but cannot  find any valid documentation anywhere.

 

I found articles with people using ADFS to do this but i got rid of ADFS not going back.

 

Does anyone have any information on whether this is possible, I have an ongoing tickect with support but were going in circles

26 REPLIES 26

RN
Community Moderator | Employee
Community Moderator | Employee

Hey @ctaveras, The best way for your picture mapping is on your organization public running in HTTPS, so you can path the picture on your mapping using the HTTPS (secure channel) and also accessible publicly (not behind the firewall). 

Also on the mapping, you should use the transformation. And follow the info below:
Name: profilepic
Source: Transformation
Transformation: Join()
Parameter1: https://your-image-server/picture example https://mydomain.com/picture (your naming convention for your save picture on the server should be same as on your user principal name)
Parameter2: user.principalname. . You can see the user principal name at user profile -> "User Principal Name"

​​​

 

You just need to have the direct URL for each photo of the users. Let me know if this provides you with some guidance! 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Zoom Community Moderator
he/him/his

Have you heard about Zoom AI Companion? ➡️ Check it out!

After researching this issue for weeks, it's clear that your customers don't want to erect a web server OUTSIDE OF OUR FIREWALL just to host some profile pictures.  For a company as large as this, it seems absurd to me (and everyone else here) that we simply cannot use a SAML attribute (say 'thumbnailPhoto' - which already exists in AD) and use that as our profile picture.

 

The reason why is because that attribute is stored as an octet string and it would require you to convert that image to base64 in order for the image to be viewable.  Here's the issue: When you convert that attribute to base64, it's too large to store in AD. It ends up being triple the allotted size for an extensionattribute.

So, why not convert the image to base64 on the backend?

I'm pretty sure this won't get a response given the thread, I'm just keeping this post alive.

RN
Community Moderator | Employee
Community Moderator | Employee

Hey @ctaveras, just checking in on my reply! Just curious if this was helpful! 🙂

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Zoom Community Moderator
he/him/his

Have you heard about Zoom AI Companion? ➡️ Check it out!

DDIT
Explorer
Explorer

Hello. I found this discussion from a google search. I understand the reply from @ctaveras , but that assumes we host our users profile pictures on a public website, which we don't. We would like to use the Azure AD profile picture, which can be discovered in the Graph API here: https://graph.microsoft.com/beta/me/photo/$value

 

However, simply creating a new claim in Azure AD and setting this as the value and creating a mapping in the ZOOM SAML Mappings doesn't work. When logging in as a user, the claim resolves to the value of "https://graph.microsoft.com/beta/me/photo/$value", not the actual user photo.

 

I'm obviously doing something wrong here. Has anyone got this working? Please post your suggestions and tips.

Thanks.

Was there ever a resolution to this where Graph was successful?

DDIT
Explorer
Explorer

Hi @glynch27  I'm still waiting for someone to post an answer. Considering Zoom's popularity, I'm surprised more people aren't asking this question and/or offering the answer. Some huge org's must have achieved this. Perhaps  I'll raise a support ticket or ask on reddit.com/r/Zoom as well. I'll post the answer here when I find it!

I am surprised as well and from a Graph API standpoint, it's fairly easy to implement into Zoom (from a dev perspective).  I'll bring this up to the channel teams as a feature request, but I think the subreddit request and in other places may create more traction.

 

For what we're able to do currently (SAML assertion), we would need to broker the image somewhere and get the user values which is crazy for us supporting large orgs (ourselves as a partner and MSSP/MSP).  Since the graph permissions are already in-place, it's an easy association of pulling the largest photo from graph and applying it to the Zoom user and could be an easy option to toggle on/off.

Very keen on some assistance here myself. It's almost 2am and I'm struggling to believe how difficult this is to achieve. We've enabled Single Sign-on, auto provisioning, and SAML response mappings and all of those are working... but I'm really struggling to find further guidance for the Profile Picture. I will watch this thread with eager anticipation of a simple solution for what seems like it should be a trivial problem.

 

cheers all

DDIT
Explorer
Explorer

@JCarvell or @glynch27 

Whilst I don't have an answer to this yet, I'm wondering if you could offer some advice on a related matter. Although we provision Zoom user accounts automatically from Azure AD, I still need to go into each account in Zoom, manually set the time zone, preferred date format (dd/mm/yyyy) and set the time zome to 24-hours. Have you worked out a way to automate or sync this from Azure? These configurable options don't appear under SAML mappings, nor anywhere else in Zoom Accounts Settings as far as I am aware. Thanks in advance.

glynch27
Zoom Partner
Zoom Partner

@DDIT @JCarvell -- Hopefully this thread will bring traction from the team, and I still need to ping my resources at Zoom to see if this is road mapped.  

 

A majority of this is very easy work but like most, it's in a bucket of hundreds of other to-do's and prioritizing it to the top can be difficult.  Especially with recent larger deals of 100k+ seats from Citi and other orgs, I find it difficult to understand some of the core basics still need addressing but, I have full confidence that they will eventually iron this out.

 

The big ones are ones you already mentioned-->

 

  • Allow the ability to sync profile picture and grant access on behalf of the company to allow all users to share profile pictures.  This process is the same as what's used for OAuth calendar and contacts sync.
  • Ability to set default time zone and / or pull IdP integration time zone (Okta, Duo, Azure, etc.) for the user

Then there's the one not really related to this thread but is in the same bucket for me to fix the "oddly not here" settings-->

  • Ability to set default caller ID (a frequent one in the forums

SAML response is limited on some of this, however, I could see time zone being incorporated and updated upon login in case the user has changed time zones.

TFBjp
Newcomer
Newcomer

anyone hear what the plans are? I assume at this point it will be with the JWT to Oath change that is due before July 2023.

haakebecks
Explorer
Explorer

Another entity looking for picture sync via Azure AD. Has anyone made progress on this? Has Zoom taken any notice at all?

alakhani
Newcomer
Newcomer

Was anybody able to get the azure profile pictures on Zoom?

haakebecks
Explorer
Explorer

Nope, no movement on this. 

AnthonySR
Newcomer
Newcomer

I'd also love to see Graph work correctly with SSO to zoom for the profile pics.

We're using workspace reservation in Zoom now for hot desks, it would be great for the pictures to auto populate on user accounts so they can easily see who is at which desks on which days etc.

DDIT
Explorer
Explorer

Just posting to keep this topic alive. I create a new Zoom support case and asked again. I was given a similar answer...

 

As for your query about syncing profile pictures from Azure AD, you may try to do this via SAML response mapping.
The basic idea for profile picture mapping is this:
1. The admin puts the profile pictures onto a web server.
2. The admin creates a basic SAML mapping for profile pictures. The mapping contains a publicly accessible URL pointing to the web server’s profile picture.
3. During the SSO process, Zoom pulls the profile picture from the web server and adds it to the user’s profile.
There is one difference when doing this with Azure AD as the IDP. The image must be base64 encoded before being placed on the server.

This ins't helpful, so I went back asking for more specifics about what that SAML response might look like (examples from other customers). It is also my understanding that the profile pic isn't available via SAML responses, and instead MS Graph is required. I also understand that MS Graph response is given in binary, so further converting to Base64 will need to be done, which is only possible in the code that made the request (Zoom's portal). If I'm correct (and I could very much be wrong) then this isn't going to work at all, unless Zoom specifically add support for grabbing the photo from MS Graph.

 

 

Does anyone else have an update?

DDIT
Explorer
Explorer

I got a quick response. The answer was

 

Based on what I have gathered you can map the profile picture by using a direct URL where the picture is located. Unfortunately, there is no specific attribute that would be able to be mapped to bring in the picture. Some of our customers have all the pictures uploaded to a file-sharing site then each picture has its own link.
 
Here is an image to clarify.

This isn't a solution, but does provide a glimpse at how using a claim transform, you are able to get unique photos for each user. It doesn't specifically work for Azure because the Graph photo still requires some authentication to get to, and still isn't' in base64 format.

 

Yes, I could put my photos on a public URL, but if I'm manually doing that, I may as well manually upload the photo to the users' Zoom account instead. 

sutro-rwhitaker
Newcomer
Newcomer

I would like to bump this post. Hosting avatar pictures on a publically accessible server is not an acceptable solution.

 

+1 to add Microsoft Graph support!

haakebecks
Explorer
Explorer

We have this working through our provisioning partner we use called Aquera.

 

We leverage them because ADP is our source of truth for employee data. We hook from Aquera into Azure AD, but also pay for the integration into Zoom because it was such a large organizational ask to get photos in and it is the only way we found to fully automate it.

 

Not cheap and we would discontinue that integration tomorrow if Zoom got their act together and simply supported MS Graph for this. 

 

Come on Zoom, Enterprise clients are asking for this and it has been years already! 

-aa-
Newcomer
Newcomer

Bumping post.

After researching this issue for weeks, it's clear that your customers don't want to erect a web server OUTSIDE OF OUR FIREWALL just to host some profile pictures.  For a company as large as this, it seems absurd to me (and everyone else here) that we simply cannot use a SAML attribute (say 'thumbnailPhoto' - which already exists in AD) and use that as our profile picture.

 

The reason why is because that attribute is stored as an octet string and it would require you to convert that image to base64 in order for the image to be viewable.  Here's the issue: When you convert that attribute to base64, it's too large to store in AD. It ends up being triple the allotted size for an extensionattribute.

So, why not convert the image to base64 on the backend?

I'm pretty sure this won't get a response given the thread, I'm just keeping this post alive.

ITWarrior
Newcomer
Newcomer

It would be great to see the SAML mapping pull the photo and import automatically into the zoom account.  Giving this a bump 🙂

cschulze2
Newcomer
Newcomer

We would like to get this feature as well. 

Maintaining profile picture for thousands of users in multiple places takes a lot of time.

jracz
Newcomer
Newcomer

I gave up on this 2 years ago and just run a daily sync job using the same images that are set for Entra. The job uses the zoom Api and the pszoom PowerShell module

DDIT
Explorer
Explorer

Wow. You are the first person I believe since this topic was created to have an automated solution. Could you share your sync job script here please?

 

Sure - here it is. Zoom doesn't keep the name of the file it's some type of hash or guid I believe so you have to keep a state file. I also have another job for if their photo in the headshot's directory is changed to delete it from the json. This way on the next run it will update in zoom. We also disabled the user's ability to update their own photos as there were some that were doing it daily. This also includes a commented out section to export all the zoom users photos. 

$Verbose = 2
$LogFileName = [string]::Format("Zoom-{0}.log", (Get-Date -Format yyyy-MM-dd))
$LogFilePath = "C:\Bin\Zoom\$LogFileName";

Function Log {
    param($message);
    if ($Verbose -ge 2) {    
        $currenttime = Get-Date -format u;
        $outputstring = "[" + $currenttime + "] " + $message;
        $outputstring | Out-File $LogFilepath -Append;
    }
}


Function LogAndConsole($message) {
    if ($Verbose -ge 1) {
        Write-Host $message -ForegroundColor Green
    }
    if ($Verbose -ge 2) {
        Log $message
    }
}

Function LogErrorAndConsole($message) {
    if ($Verbose -ge 1) {
        Write-Host $message -ForegroundColor Red
    }
    if ($Verbose -ge 2) {
        Log $message
    }
}

import-Module PSZoom
#update zoom creds if changed
#Get-Credential | Export-Clixml "C:\Bin\Zoom\ZoomAPI.xml" -Force
$zoomAPI = Import-Clixml "C:\Bin\Zoom\ZoomAPI.xml"
$zoomAPIsplat = @{
    AccountID    = $zoomAPI.GetNetworkCredential().Domain
    ClientID     = $zoomAPI.GetNetworkCredential().UserName
    ClientSecret = $zoomAPI.GetNetworkCredential().Password
}
try {
    Log 'Connecting to zoom'
    connect-PSZoom @zoomAPIsplat -ErrorAction Stop
}
catch {
    LogErrorAndConsole "[!] Quitting - $($_.Exception.Message)"
    break
}


$headshotsPath = "\\(pathhere)\Headshots"

######Export Current Zoom Images######
<#
foreach ($user in $zoomUsers){
    if ($null -ne $user.pic_url){
        $url  = $user.pic_url + '?type=large'
    Invoke-WebRequest -uri $url -OutFile \\$headshotsPath\Headshots\Zoom\Old\$($User.email).jpg
    }
}
#>

#Get Current Zoom users and dump to json
$zoomUsers = Get-ZoomUsers -AllPages | Select-Object email, pic_url
$zoomUsers | ConvertTo-Json | Out-File c:\bin\zoom\zoomUsersCurrent.json -Force
$zoomLocal = Get-Content c:\bin\zoom\zoomUsersUpdated.json | ConvertFrom-Json
$diffs = Compare-Object $zoomUsers $zoomLocal -Property pic_url -PassThru | Where-Object sideindicator -eq '<='

$zoomChangeLog = "ZoomChangeLog-" + (Get-Date -Format yyyy-MM-dd) + '.txt'

foreach ($diff in $diffs) {
    $email = $diff.email
    $User = Get-ADUser -Filter { UserPrincipalName -eq $email }
    $picturePath = "\\$headshotsPath\Headshots\$($User.SamAccountName)" + ".jpg"
    if (Test-Path -Path $picturePath) {
        $original = [System.Drawing.Image]::FromFile($picturePath)
        $ratioX = 648 / $original.Width
        $ratioY = 648 / $original.Height
        $ratio = $ratioY
        if ($ratioX -le $ratioY) {
            $ratio = $ratioX
        }
        
        # Resize the picture
        [int]$newWidth = $original.Width * $ratio
        [int]$newHeight = $original.Height * $ratio
        
        $newPicture = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
        $graph = [System.Drawing.Graphics]::FromImage($newPicture)
        
        $graph.Clear([System.Drawing.Color]::White)
        $graph.DrawImage($original, 0, 0, $newWidth, $newHeight)
        
        # Set encoder settings for image quality
        $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
        $encoder = [System.Drawing.Imaging.Encoder]::Quality
        $encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($encoder, 100)
        
        # Save file
        $tmpFilePath = "C:\bin\zoom\upload\$($User.SamAccountName)" + ".jpg"
        $imageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.MimeType -eq 'image/jpeg' }
        $newPicture.Save($tmpFilePath, $imageCodecInfo, $($encoderParams))

        $upload = update-ZoomProfilePicture -UserId $email -FileName $tmpFilePath
        LogandConsole "Updated $($upload.id) at $($upload.added_at)"

        [System.IO.File]::Delete($tmpFilePath)
        # Release resources
        if ($original) { $original.Dispose() }
        if ($graph) { $graph.Dispose() }
        if ($newPicture) { $newPicture.Dispose() }
    }
}

$zoomUsersUpdated = Get-ZoomUsers -AllPages | Select-Object email, pic_url
$zoomUsersUpdated | where pic_url -NE $null | ConvertTo-Json | Out-File c:\bin\zoom\zoomUsersUpdated.json -Force
$zoomUsersUpdated.count

  

DDIT
Explorer
Explorer

This is amazing. Thank you. I'll give it a read and digest the code later. Thanks in advance for all your hard work and willingness to share!