What character encoding should a POST body to /v1.0/users have?
I have problems with generating users with accented characters in the name with Microsoft Graph.
I use the following body:
{
"accountEnabled":false,
"displayName":"ADM Joost Müller",
"userprincipalname":"admjmuller@mytenant.onmicrosoft.com",
"mailNickname":"admjmuller",
"passwordProfile":{
"forceChangePasswordNextSignIn":true,
"forceChangePasswordNextSignInWithMfa":true,
"password":"Randompasswordgenerated"
}
}
When calling POST to /v1.0/users with the above JSON in the body I get the following object back:
@odata.context : https://graph.microsoft.com/v1.0/$metadata#users/$entity
id : xxxxxxxx-xxxx-xxxx-xxxx-a72a188e6d9a
businessPhones : {}
displayName : ADM Joost M�ller
givenName :
jobTitle :
mail :
mobilePhone :
officeLocation :
preferredLanguage :
surname :
userPrincipalName : admjmuller@mytenant.onmicrosoft.com
Note the '�' in the displayname. This is NOT a display problem in Powershell, the Entra ID blade in the Azure portal also shows this character. I've already tried to forcibly convert the JSON to UTF-8:
$enc = [System.Text.Encoding]::UTF8
$jsonutf8 = $enc.getstring($enc.getbytes($json))
but that didn't solve the problem.
I've tried various search terms but can't find anything that points to a solution. It's probably something trivial but if it is, I'm using the wrong search terms...
The actual code:
function Encode {
Param(
[string]$text
)
$enc = [System.Text.Encoding]::Utf8
return $enc.getstring($enc.getbytes($text))
}
function Invoke-GraphPost {
[cmdletbinding()]
Param(
[parameter(Mandatory = $true)][string]$API,
[parameter(Mandatory = $true)][string]$AccessToken,
[parameter(Mandatory = $true)]$body,
[parameter(Mandatory = $false)][string]$Apiversion = "v1.0"
)
$header = @{
Authorization = ("Bearer {0}" -f $AccessToken)
'Content-Type' = 'application/json; charset=utf-8'
}
$bodyjson = Encode(ConvertTo-Json -InputObject $body -Compress)
$URI = Encode(("https://graph.microsoft.com/{0}/{1}" -f $Apiversion, $API))
try {
$result = Invoke-RestMethod -Uri $URI -Method Post -Body $bodyjson -Headers $header
}
catch {
$FailMessage = ("Unable to create graph POST request {0} with body {1}" -f $URI, $bodyjson)
$module.failjson($FailMessage)
}
return $result
}
$password = [System.Web.Security.Membership]::GeneratePassword(12, 4)
$upnbase = New-EntraUserName -NameFormat "$adminprefix$format" -Voornaam $User.Roepnaam -Infix $User.Voorv_gebnaam -Achternaam $User.Geboortenaam -Domainname $admindomain
$body = @{
accountEnabled = $false
displayName = ("ADM {0} {1}" -f $User.Roepnaam.Trim(), $User.Volledige_achternaam.Trim())
mailNickname = $upnbase
userprincipalname = ("{0}@{1}" -f $upnbase, $admindomain)
passwordProfile = @{
forceChangePasswordNextSignIn = $true
forceChangePasswordNextSignInWithMfa = $true
password = $password
}
}
$newuser = Invoke-GraphPost -API users -AccessToken $token.access_token -body $body
where New-EntraUserName
generates a unique username based on givenname, infix and surname (that exact code is irrelevant for the problem, for Joost Müller, the generated username is admjmuller, so without accent).
Joost
Your request body is not being submitted with the expected UTF-8 character encoding, for the following reasons:
Your Encode
function is a no-op: it converts a string to and back from a UTF-8 byte representation, so that you're ending up with the same .NET string (of type [string]
, which is internally composed of UTF-16 Unicode code units).
Thus, you're passing a regular [string]
instance to the -Body
parameter and are therefore delegating the decision as to what character encoding to use to
Invoke-RestMethod
(the following applies analogously to Invoke-WebRequest
as well):
While you're trying to indicate the desired encoding via a header field, - the 'Content-Type' = 'application/json; charset=utf-8'
entry in the hashtable you're passing to -Header
- PowerShell 7.3-, including Windows PowerShell, unfortunately does not honor this, and default to ISO-8559-1 encoding.
charset
attribute as part of the separate -ContentType
parameter is honored (see below).PowerShell (Core) 7.4+ now honors a header field too and in the absence of a charset
attribute now defaults to UTF-8.
Solutions:
PowerShell 7.4+:
Encode
call.PowerShell 7.3- and Windows PowerShell:
Option 1:
Encode
call.Content-Type
entry to $header
.-ContentType 'application/json; charset=utf-8'
argument to the Invoke-RestMethod
call.Option 2:
Perform the UTF-8 encoding yourself and pass a byte array to the -Body
parameter:
Invoke-RestMethod -Uri $URI -Method Post -Headers $header -Body (
[Text.UTF8Encoding]::new().GetBytes(
(ConvertTo-Json -InputObject $body -Compress)
)
)