The script updates a user photo in AD and Microsoft 365 using the value stored in a Binary attribute of the user. To run the script, create a custom command, business rule or scheduled task configured for the User object type.
Parameters:
- $copyFromPropertyName - Specifies the LDAP name of the Binary attribute storing the picture to be set.
- $photoAttribute - Specifies the LDAP name of the attribute that will be updated with the picture stored in the attribute specified in the $copyFromPropertyName variable.
PowerShell
$copyFromPropertyName = "adm-CustomAttributeBinary1" # TODO: modify me
$photoAttribute = "thumbnailPhoto" # TODO: modify me
function ResizePhoto ($photoBytes, $maxSize, $reduceSizeStep, $reduceSizeInPercents, $maxWidth, $maxHeight)
{
if ($reduceSizeInPercents -ge 100)
{
return ,$photoBytes
}
try
{
# Calculate the new size, preserve ratio
$original = [System.Drawing.Image]$photoBytes
$width = $original.Width
$height = $original.Height
if ($NULL -ne $maxWidth)
{
if ($width -le $maxWidth -and $height -le $maxHeight)
{
return ,$photoBytes
}
$ratioX = $maxWidth / $width
$ratioY = $maxHeight / $height
}
else
{
$ratioX = ($width - (($width / 100) * $reduceSizeInPercents)) / $width
$ratioY = ($height - (($height / 100) * $reduceSizeInPercents)) / $height
}
$ratio = $ratioY
if ($ratioX -le $ratioY)
{
$ratio = $ratioX
}
# Resize the picture
[int]$newWidth = $width * $ratio
[int]$newHeight = $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()
}
finally
{
# Release resources
if ($original) { $original.Dispose() }
if ($graph) { $graph.Dispose() }
if ($newPicture) { $newPicture.Dispose() }
if ($memoryStream) { $memoryStream.Dispose() }
}
if (($NULL -ne $maxSize) -and
($newPictureBytes.Length -gt $maxSize))
{
$reduceSizeInPercents += $reduceSizeStep
$newPictureBytes = ResizePhoto $photoBytes $maxSize $reduceSizeStep $reduceSizeInPercents
}
return ,$newPictureBytes
}
# Get the picture
try
{
$photoBytes = $Context.TargetObject.Get($copyFromPropertyName)
}
catch
{
$Context.LogMessage("No picture specified in attribute $copyFromPropertyName.", "Warning")
return # No picture
}
# Update thumbnailPhoto
$maxSize = 102400
if ($photoBytes.Length -gt $maxSize)
{
$thumbnailPhotoBytes = ResizePhoto $photoBytes $maxSize 1 0 $NULL $NULL
}
else
{
$thumbnailPhotoBytes = $photoBytes
}
$Context.TargetObject.Put($photoAttribute, $thumbnailPhotoBytes)
$Context.TargetObject.SetInfo()
if ($NULL -eq $Context.TargetObject.AzureID)
{
$Context.LogMessage("User %fullname% has no account in Microsoft 365.", "Warning")
return
}
$userPhotoBytes = ResizePhoto $photoBytes $NULL $NULL $NULL 648 648
# 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
}
It should be possible using the Get-UserPhoto cmdlet in the script. However, starting from Adaxes 2023, you can manage Azure AD objects directly. Meaning that you can use much simpler approaches to achieve the same.