
I have created a simple script that can bulk-update user’s profile photos in Azure AD / M365. All you need to do is put all the pictures in a folder, name the files with the user’s UPN and run my script. The script needs a Graph API permission called User.ReadWrite.All (application rights), so you need to create an Azure App Registration. Take a look at my previous blog post here to see how you set permissions and get the secret/client id/tenant id. There are some limitations to the profile picture as you see from this quote from the Graph API Docs:

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### Azure AD / M365 profile picture uploader | |
### Version 1.0 | |
### Author: Alexander Holmeset | |
### Email: [email protected] | |
### Twitter: twitter.com/alexholmeset | |
### Blog: alexholmeset.blog | |
$TenantId = "xxxxxxx" | |
$ClientID = "xxxxxx" | |
$ClientSecret = "xxxxx" | |
#Folder where you have the profilepictures. | |
$filefolder = "c:\temp\" | |
function Get-MSGraphAppToken{ | |
<# .SYNOPSIS | |
Get an app based authentication token required for interacting with Microsoft Graph API | |
.PARAMETER TenantID | |
A tenant ID should be provided. | |
.PARAMETER ClientID | |
Application ID for an Azure AD application. Uses by default the Microsoft Intune PowerShell application ID. | |
.PARAMETER ClientSecret | |
Web application client secret. | |
.EXAMPLE | |
# Manually specify username and password to acquire an authentication token: | |
Get-MSGraphAppToken -TenantID $TenantID -ClientID $ClientID -ClientSecert = $ClientSecret | |
.NOTES | |
Author: Jan Ketil Skanke | |
Contact: @JankeSkanke | |
Created: 2020-15-03 | |
Updated: 2020-15-03 | |
Version history: | |
1.0.0 - (2020-03-15) Function created | |
#> | |
[CmdletBinding()] | |
param ( | |
[parameter(Mandatory = $true, HelpMessage = "Your Azure AD Directory ID should be provided")] | |
[ValidateNotNullOrEmpty()] | |
[string]$TenantID, | |
[parameter(Mandatory = $true, HelpMessage = "Application ID for an Azure AD application")] | |
[ValidateNotNullOrEmpty()] | |
[string]$ClientID, | |
[parameter(Mandatory = $true, HelpMessage = "Azure AD Application Client Secret.")] | |
[ValidateNotNullOrEmpty()] | |
[string]$ClientSecret | |
) | |
Process { | |
$ErrorActionPreference = "Stop" | |
# Construct URI | |
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" | |
# Construct Body | |
$body = @{ | |
client_id = $clientId | |
scope = "https://graph.microsoft.com/.default" | |
client_secret = $clientSecret | |
grant_type = "client_credentials" | |
} | |
try { | |
$MyTokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing | |
$global:MyToken =($MyTokenRequest.Content | ConvertFrom-Json).access_token | |
If(!$MyToken){ | |
Write-Warning "Failed to get Graph API access token!" | |
Exit 1 | |
} | |
$MyHeader = @{"Authorization" = "Bearer $global:MyToken "} | |
} | |
catch [System.Exception] { | |
Write-Warning "Failed to get Access Token, Error message: $($_.Exception.Message)"; break | |
} | |
return $MyHeader | |
} | |
} | |
#Generates Graph API token. | |
$Header = Get-MSGraphAppToken -TenantID $TenantId -ClientID $ClientID -ClientSecret $ClientSecret | |
$Header = @{"Authorization" = "Bearer $global:MyToken" ;'Content-Range' = "bytes 0-$($fileLength-1)/$fileLength";"content-type" = "image/jpeg"} | |
#Load profile pictures from folder. | |
$files = get-childitem -path $filefolder | select-object Extension,name | |
foreach($file in $files){ | |
#Path of the current file | |
$path = $filefolder+$($file.name) | |
#Convert profile picture to bytes. | |
$fileInBytes = [System.IO.File]::ReadAllBytes($path) | |
$fileLength = $fileInBytes.Length | |
$upn = @() | |
$upn = ($file.name).replace(($($file.Extension)),"") | |
$URI = "https://graph.microsoft.com/v1.0/users/$upn/photo/`$value/" | |
$response = Invoke-RestMethod -Method 'Put' -Uri $URI -Body $fileInBytes -Headers $Header | |
} |
[…] I have created a simple script that can bulk-update user’s profile photos in Azure AD / M365. All you need to do is put all the pictures in a folder, name the files with the user’s UPN and run my script. The script needs a Graph API permission called User.ReadWrite.All (application rights), so you need… — Read on alexholmeset.blog/2022/10/23/azure-ad-m365-profile-picture-uploader/ […]
LikeLike