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":"[email protected]",
"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 : [email protected]
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
Encodefunction 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-Bodyparameter and are therefore delegating the decision as to what character encoding to use toInvoke-RestMethod(the following applies analogously toInvoke-WebRequestas 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.charsetattribute as part of the separate-ContentTypeparameter is honored (see below).PowerShell (Core) 7.4+ now honors a header field too and in the absence of a
charsetattribute now defaults to UTF-8.Solutions:
PowerShell 7.4+:
Encodecall.PowerShell 7.3- and Windows PowerShell:
Option 1:
Encodecall.Content-Typeentry to$header.-ContentType 'application/json; charset=utf-8'argument to theInvoke-RestMethodcall.Option 2:
Perform the UTF-8 encoding yourself and pass a byte array to the
-Bodyparameter: