发送到 /v1.0/users 的 POST 正文应该采用什么字符编码?
我在使用 Microsoft Graph 生成名称中带有重音字符的用户时遇到问题。
我使用以下身体:
{
"accountEnabled":false,
"displayName":"ADM Joost Müller",
"userprincipalname":"[email protected]",
"mailNickname":"admjmuller",
"passwordProfile":{
"forceChangePasswordNextSignIn":true,
"forceChangePasswordNextSignInWithMfa":true,
"password":"Randompasswordgenerated"
}
}
当在正文中使用上述 JSON 调用 POST 到 /v1.0/users 时,我得到以下对象:
@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]
注意显示名称中的“�”。这不是 Powershell 中的显示问题,Azure 门户中的 Entra ID 边栏选项卡也显示此字符。 我已经尝试过将 JSON 强制转换为 UTF-8:
$enc = [System.Text.Encoding]::UTF8
$jsonutf8 = $enc.getstring($enc.getbytes($json))
但这并没有解决问题。
我尝试了各种搜索词,但找不到任何指向解决方案的内容。这可能是一件微不足道的事情,但如果是的话,我使用了错误的搜索词......
实际代码:
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
其中
New-EntraUserName
根据名字、中缀和姓氏生成唯一的用户名(确切的代码与问题无关,对于 Joost Müller,生成的用户名是 admjmuller,因此没有重音)。
乔斯特
您的 请求正文未以预期的 UTF-8 字符编码提交,原因如下:
您的
Encode
函数是一个 no-op:它将字符串转换为 并从 UTF-8 字节表示形式返回,这样您最终会得到相同的 .NET 字符串(类型为[string]
,内部由UTF-16 Unicode代码单元组成)。
因此,您将常规
[string]
实例传递给 -Body
参数,因此将使用哪种字符编码的决定委托给Invoke-RestMethod
(以下内容也类似地适用于Invoke-WebRequest
):
当您尝试通过 header 字段指示所需的编码时, - 您传递给
'Content-Type' = 'application/json; charset=utf-8'
的哈希表中的 -Header
条目 - PowerShell 7.3-,包括 Windows PowerShell ,不幸的是,不遵守这一点,并且默认为ISO-8559-1编码。
charset
属性作为单独的 -ContentType
参数PowerShell(核心) 7.4+ 现在也支持标头字段,并且在 charset
属性的缺席中,现在默认为 UTF-8。
解决方案
:PowerShell 7.4+
:鉴于上述情况,您的代码应该按原样工作 - 除了您不需要多余的
Encode
PowerShell 7.3-和 Windows PowerShell
:省略(毫无意义的)
Encode
请勿将
Content-Type
条目添加到
$header
-ContentType 'application/json; charset=utf-8'
调用添加 Invoke-RestMethod
参数。
执行UTF-8编码自己并将字节数组传递给-Body
Invoke-RestMethod -Uri $URI -Method Post -Headers $header -Body (
[Text.UTF8Encoding]::new().GetBytes(
(ConvertTo-Json -InputObject $body -Compress)
)
)