Reputation: 77
Our company is migrating user info to our Microsoft tenant. Part of this info includes the profile picture.
Most of the information I am able to update using Set-MSolUser, but for the profile picture I've been trying to use Microsoft Graph, with no success.
I am a tenant admin and yet I've had no success in updating users' profile pictures. Here's my code:
$token = [my-token]
$Headers = @{
"Authorization" = "Bearer $token"
"Content-Type" = "image/jpeg"
}
Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/users/{user-id}/photo/$value' -Method Put -Headers $Headers
This has just been for test purposes so I'm trying with a single user id and no picture. This has been the output:
"error": {
"code": "ErrorAccessDenied",
"message": "AccessDeniedException",
And the same thing happens when querying directly through the graph website:
Per the documentation, certain permissions are necessary (contact, group or user read.write) which I have ticked all on the Graph website, but still nothing.
Any ideas would be greatly appreciated.
Upvotes: 1
Views: 1999
Reputation: 4634
Under user permissions you able to edit only your own picture.
You have to create an Azure AD application with User.ReadWrite.*All*
permission to edit others' pictures.
Go to:
portal.azure.com -> Active Directory -> App Registration -> New Registration
. Then under API permissions
you grant User.ReadWrite.All
and click grant admin consent
. Then under Certificates and Secrets
you create an app secret.
$AzAppSecret = 'abcDEFghiJKLmnoPQRstuVWXyz01234567' # from AzureAD -> App Registrations -> YourApp -> Certificates & secrets
$AzAppId = 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA' # from AzureAD -> App Registrations -> YourApp -> Overview -> Application (client) ID
$AzTenantId = 'BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB' # from AzureAD -> App Registrations -> YourApp -> Overview -> Directory (tenant) ID
$AzUserUPN = '[email protected]' # from AzureAD -> Users -> YourUser -> User Principal Name
$AzUserImage = 'S:\samplepic.jpg' # Jpeg file
# Request token
$tokenRequestBody = @{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
Client_Id = $AzAppID
Client_Secret = $AzAppSecret
}
$tokenRequestUri = [String]::Format('https://login.microsoftonline.com/{0}/oauth2/v2.0/token', $AzTenantId)
$tokenResponse = Invoke-RestMethod -Uri $tokenRequestUri -Method 'POST' -Body $tokenRequestBody -ErrorAction Stop
$accessToken = $tokenResponse.access_token
$uri = [String]::Format('https://graph.microsoft.com/v1.0/users/{0}/photo/$value', $AzUserUPN)
$Headers = @{
'Authorization' = [String]::Format('Bearer {0}', $accessToken)
'Content-Type' = 'image/jpeg'
}
Invoke-RestMethod -Method Put -Uri $uri -InFile $AzUserImage -Headers $Headers
# Load Assembly System.Net.Http
# In PS7 built-in, on PS5 - Download NuGet package from https://www.nuget.org/packages/System.Net.Http/ and unzip using 7zip
[void][System.Reflection.Assembly]::LoadFile('P:\path-to\system.net.http.4.3.4\runtimes\win\lib\netstandard1.3\System.Net.Http.dll')
# Prepare httpClient and URI
$httpClient = [System.Net.Http.HttpClient]::new()
$httpClient.DefaultRequestHeaders.Authorization = [String]::Format('Bearer {0}', $accessToken)
# Prepare Content
$content = [System.Net.Http.ByteArrayContent]::new([System.IO.File]::ReadAllBytes($AzUserImage));
$content.Headers.ContentType = "image/jpeg";
# Run
$task = $httpClient.PutAsync($uri,$content)
$task.Wait()
$task.Result.IsSuccessStatusCode
Upvotes: 2
Reputation: 59318
This is expected error in case if
User.ReadWrite.All
permission is missing when calling this Microsoft Graph endpointDocumentation says the following in this regard:
update the photo of any user in the organization, your app must have the
User.ReadWrite.All
application permission and call this API under its own identity, not on behalf of a user
And last but not least, profile image is expected to be passed via request body, in case of PowerShell the request could be constructed like this:
$Headers = @{
"Authorization" = "Bearer $access_token"
"Content-Type" = "image/jpeg"
}
$url = "https://graph.microsoft.com/v1.0/users/$($userId)/photo/$value"
$profilePath = "--path to profile file--"
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users/$($userId)/photo/$value" -Method Put -InFile $profilePath -Headers $Headers
Upvotes: 1