Microsoft 365
Sync Microsoft 365 Profile Pictures with Interact
Use PowerShell to download Profile Pictures from Microsoft 365 and then upload into Interact. The scripts can be scheduled to run using Windows Task Scheduler at suitable intervals.
Prerequisites
- A General Source Profile in Interact. See article General Profile Sources
- Download and install the ExchangeOnlineManagement PowerShell Package from:
https://www.powershellgallery.com/packages/ExchangeOnlineManagement/2.0.5 - Run the following command in PowerShell
Import-Module ExchangeOnlineManagement
You may have to set the PowerShell execution policy to RemoteSigned or Unrestricted using the following command Set-ExecutionPolicy RemoteSigned or Set-ExecutionPolicy Unrestricted
Microsoft 365 Permissions
- Global administrator or Exchange administrator role in Microsoft 365
- ApplicationImpersonation role in Exchange Online
Download Script
The following script can be used to download all users profile pictures and store them here C:\O365\AllUserProfilePictures, it will then upload them to Interact. In this example the ExternalDirectoryObjectId field will be used for the filename, for example 14f90941-8aab-49d7-963b-841962dea5e9.jpg. Interact will use this GUID to associate it with the correct user profile by mapping it against the UMIID. See the article Profile Pictures for more examples of what can be used to map the exported pictures to the interact profile, username for example.
#Input Parameters:
$folderpath = "c:\O365\AllUserProfilePictures"
$logpath = "c:\O365\log.txt"
#Connect to Exchange Online:
$UPN = "[email protected]"
$Password = ConvertTo-SecureString "password" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($UPN, $Password)
Connect-ExchangeOnline -Credential $Credential
#Interact variables
$interactUrl = "https://example.interactgo.com"
$profileSourceApiKey = "1234"
$profileSourceId = "1000"
#Download all user profile pictures from Microsoft 365:
New-Item -ItemType directory -Path $folderpath -Force
$allUsers = Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited | Select-Object UserPrincipalName, Alias, ExternalDirectoryObjectId
foreach ($user in $allUsers) {
$path = Join-Path $folderpath "$($user.ExternalDirectoryObjectId).jpg"
try {
$photo = Get-UserPhoto -Identity $user.UserPrincipalName -ErrorAction continue
if ($photo.PictureData -ne $null) {
[io.file]::WriteAllBytes($path, $photo.PictureData)
$message = "$($user.UserPrincipalName) profile picture downloaded"
Write-Output $message
Add-Content -Path $logpath -Value $message
}
else {
$message = "$($user.UserPrincipalName) has no profile picture"
Write-Output $message
Add-Content -Path $logpath -Value $message
}
}
catch {
$errorMessage = "Error downloading profile picture for $($user.UserPrincipalName): $($_.Exception.Message)"
Write-Error $errorMessage
Add-Content -Path $logpath -Value $errorMessage
}
}
#UPLOAD TO INTERACT
Add-Type -AssemblyName System.Net.Http
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
function ProcessFiles(){
Get-ChildItem $folderpath |
Foreach-Object {
$personId = $_.BaseName
$baseUri = $interactUrl + "/api/umi/" + $profileSourceId + "/upload/umiid/" + $personId + "/picture"
SendFile $baseUri $_.FullName
}
}
function SendFile([string]$uri, [string]$path){
$httpClientHandler = New-Object System.Net.Http.HttpClientHandler
$httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler
$packageFileStream = New-Object System.IO.FileStream @($path, [System.IO.FileMode]::Open)
$contentDispositionHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data"
$contentDispositionHeaderValue.Name = "fileData"
$contentDispositionHeaderValue.FileName = (Split-Path $path -leaf)
$streamContent = New-Object System.Net.Http.StreamContent $packageFileStream
$streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue
$streamContent.Headers.ContentType = New-Object System.Net.Http.Headers.MediaTypeHeaderValue "image/jpeg"
$content = New-Object System.Net.Http.MultipartFormDataContent
$content.Add($streamContent)
$httpClient.DefaultRequestHeaders.Add("X-ApiKey", $profileSourceApiKey)
try
{
$response = $httpClient.PostAsync($Uri, $content).Result
}
catch [Exception]
{
# log it
}
finally
{
if($null -ne $httpClient)
{
$httpClient.Dispose()
}
if($null -ne $response)
{
$response.Dispose()
}
}
}
ProcessFiles
Updated about 1 year ago