We use cookies to improve your experience.
By your continued use of this site you accept such use.
For more details please see our privacy policy and cookies policy.

Script Repository

Upload user photo to Microsoft 365

November 06, 2023 Views: 15410

The scripts upload a user photo to Microsoft 365 (Office 365). The photo will appear in client applications, such as Microsoft Outlook Web App, Lync, Skype for Business, and SharePoint.

1. Upload image stored in AD attribute

The script uploads a user photo stored in the specified property to Microsoft 365. In the script, the $propertyName variable specifies the LDAP name of the property from which to obtain user photo.

Edit Remove
PowerShell
$propertyName = "thumbnailPhoto" # TODO: modify me

if ($NULL -eq $Context.TargetObject.AzureID)
{
    $Context.LogMessage("User %fullname% has no account in Microsoft 365.", "Warning")
    return
}

# Get the photo
try
{
    $userPhotoBytes = $Context.TargetObject.Get($propertyName)
}
catch
{
    $Context.LogMessage("User %fullname% has no photo in property $propertyName.", "Warning")
    return
}

# Connect to Microsoft Graph PowerShell
$accessToken = $Context.CloudServices.GetAzureAuthAccessToken()
Connect-MgGraph -AccessToken ($accessToken | ConvertTo-SecureString -AsPlainText -Force)

try
{
    # Create temp file
    $tempFile = New-TemporaryFile
    [System.Io.File]::WriteAllBytes($tempFile.FullName, $userPhotoBytes)
    
    # Update the user's photo
    Set-MgUserPhotoContent -UserId $Context.TargetObject.AzureID -InFile $tempFile.FullName
}
finally
{
    # Remove the temp file
    Remove-Item $tempFile -Force
}

2. Upload image from file

The script uploads a photo to Microsoft 365 from a file. The image will be optimized for the best viewing quality in Microsoft 365 (Office 365) (648x648 pixels, best JPEG compression quality).

Parameter:

  • $picturePath - Specifies a path to the image file. You can use value references in the path (e.g. %username%). When the script is executed, they will be replaced with corresponding property values of the target user.
Edit Remove
PowerShell
$userPhotoPath = "\\SERVER\share\%username%.jpg" # TODO: modify me

function ResizePhoto ($picturePath)
{
    try
    {
        # Calculate the new size, preserve ratio
        $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)

        $memoryStream = New-Object System.IO.MemoryStream
        $newPicture.Save($memoryStream, [System.Drawing.Imaging.ImageFormat]::Jpeg)
        $newPictureBytes = $memoryStream.ToArray()
        
        return ,$newPictureBytes
    }
    finally
    {
        # Release resources
        if ($original) { $original.Dispose() }
        if ($graph) { $graph.Dispose() }
        if ($newPicture) { $newPicture.Dispose() }
        if ($memoryStream) { $memoryStream.Dispose() }
    }
}

if ($NULL -eq $Context.TargetObject.AzureID)
{
    $Context.LogMessage("User %fullname% has no account in Microsoft 365.", "Warning")
    return
}

# Get the photo
if (-not(Test-Path -Path $userPhotoPath))
{
    $Context.LogMessage("File '$picturePath' does not exist.", "Warning")
    return
}

$userPhotoBytes = ResizePhoto $userPhotoPath

# Connect to Microsoft Graph PowerShell
$accessToken = $Context.CloudServices.GetAzureAuthAccessToken()
Connect-MgGraph -AccessToken ($accessToken | ConvertTo-SecureString -AsPlainText -Force)

try
{
    # Create temp file
    $tempFile = New-TemporaryFile
    [System.Io.File]::WriteAllBytes($tempFile.FullName, $userPhotoBytes)
    
    # Update the user's photo
    Set-MgUserPhotoContent -UserId $Context.TargetObject.AzureID -InFile $tempFile.FullName
}
finally
{
    # Remove the temp file
    Remove-Item $tempFile -Force
}
Comments 13
avatar
MG Jan 15, 2020
If there is no picture in AD but there is currently a picture in Office365, will this overwrite the Office365 picture?
avatar
Support Jan 15, 2020

Hello,

If there is no picture in the proeprty (first script) or there is no file by the specified path (second script), the script will exit and not perform any updates in Office 365.

avatar
Ethan Jun 16, 2020
When I ran the second command, I received an error: "Error on proxy command 'Set-UserPhoto -PictureData:... The WinRM client cannot process the request. The connection string should be of the form...." I changed the connection URI from "https://ps.outlook.com/powershell/?proxymethod=rps" to "https://outlook.office365.com/powershell-liveid/" and it started working. Source: https://docs.microsoft.com/en-us/powershell/exchange/connect-to-exchange-online-powershell?view=exchange-ps
avatar
Support Jun 17, 2020

Hello Ethan,

Thank you for your feedback. The error you faced is a known issue with the Set-UserPhoto cmdlet. It occurs randomly and might depend on temporary network inconsistencies. Changing the connection URI does not fix the issue permanently.

For your information, Basic authentication used in the script will no longer be supported by Microsoft from October 2020. So, we would recommend you to update your script to connect to Exchange Online using the method described in the Exchange Online using EXO V2 module section of the following article in our repository: https://www.adaxes.com/script-repository/connect-to-exchange-with-powershell-s506.htm.

avatar
Ben Jul 15, 2020
Is there a script for the opposite of this script? We would like to sync 365 avatars to Adaxes.
avatar
Support Jul 16, 2020

Hello Ben,

Sorry for the confusion, but we are not sure what exactly you need to achieve. Do you want to get user pictures from Microsoft 365 and save to the thumbnailPhoto property in on-premises Active Directory?

 

avatar
Jason Aug 28, 2020
I would like to do this. Our users have uploaded their own photos in 365 and we would like them to be visible in AD/Adaxes.
avatar
Support Aug 28, 2020

Hello Jason,

Have a look at the following script from our repository: https://www.adaxes.com/script-repository/set-user-photo-from-microsoft-365-in-ad-s581.htm.

avatar
Richard Mar 15, 2021
Hi Team

I have run the Upload image stored in AD attribute in bulk script but it is failing with the following error:You cannot call a method on a null-valued expression. Stack trace: at <ScriptBlock>, <No file>: line 17
avatar
Support Mar 15, 2021
Hello Richard,

For troubleshooting purposes, please, specify what version of Adaxes you are currently using. For information on how to check it, have a look at the following help article: https://www.adaxes.com/help/CheckServiceVersion.

Also, post here or send us (support@adaxes.com) the script you are using with all the modifications in TXT format.
avatar
Cory Fiala Nov 21, 2023
Just wanted to share my modification that will be useful for others as well I'm sure. We use GAM (command line tool for Google Workspace) and wanted to incorporate it to update both Google and O365 photos.

--

$propertyName = "thumbnailPhoto" # TODO: modify me

if ($NULL -eq $Context.TargetObject.AzureID)
{
$Context.LogMessage("User %fullname% has no account in Microsoft 365.", "Warning")
return
}

# Get the photo
try
{
$userPhotoBytes = $Context.TargetObject.Get($propertyName)
}
catch
{
$Context.LogMessage("User %fullname% has no photo in property $propertyName.", "Warning")
return
}

# Connect to Microsoft Graph PowerShell
$accessToken = $Context.CloudServices.GetAzureAuthAccessToken()
Connect-MgGraph -AccessToken ($accessToken | ConvertTo-SecureString -AsPlainText -Force)

try
{
# Create temp file for Microsoft 365
$tempFile365 = New-TemporaryFile
[System.IO.File]::WriteAllBytes($tempFile365.FullName, $userPhotoBytes)

# Update the user's photo in Microsoft 365
Set-MgUserPhotoContent -UserId $Context.TargetObject.AzureID -InFile $tempFile365.FullName

# Create temp file for Google
$userEmail = $Context.TargetObject.Get("mail") # Assuming 'mail' attribute has the email
$tempFileGoogle = New-TemporaryFile
$googlePhotoFileName = "$($tempFileGoogle.DirectoryName)\$userEmail.jpg"
[System.IO.File]::WriteAllBytes($googlePhotoFileName, $userPhotoBytes)

# Update the user's photo in Google
gam user $userEmail update photo $googlePhotoFileName
}
finally
{
# Remove the temp files
Remove-Item $tempFile365 -Force
Remove-Item $googlePhotoFileName -Force
}
avatar
Paul Mar 09, 2024
This does not work with Adaxes version 3.16.21627.0 (and possibly earlier).
It will throw an error "“Authentication needed. Please call Connect-MgGraph. Stack trace: at Set-MgUserPhotoContent<Process>,..."

I had to upgrade to 3.16.21906.0 to get it to work.
avatar
Support Mar 11, 2024
Hello Paul,

Unfortunately, this is a known issue. Upgrading to the latest version is exactly the way to resolve the issue.
Leave a comment
Loading...

Got questions?

Support Questions & Answers