OneLogin REST API 与 PowerShell 的 Invoke-RestMethod

OneLogin REST API with PowerShell's Invoke-RestMethod

我正在使用 OneLogin REST API,似乎无法通过 PUT 方法进行任何调用。当我在 Postman 中测试时,我可以像这样传递一个原始的 JSON 正文:

{
   "role_id_array":  [
                        115028
                     ]
}

到终点:

https://api.us.onelogin.com/api/1/users//add_roles

这很好用。但是,当我尝试对 PowerShell 的 Invoke-RestMethod 命令执行相同操作时,我收到 400 Bad Request 错误。我的代码如下所示:

$Splat = @{
    Method      = $Method
    Uri         = https://api.us.onelogin.com/api/1/users/12345678/add_roles
    ContentType = "application/json"
    Headers     = @{authorization = "bearer:$($Token.access_token)"}
    Body        = @{role_id_array = @(123456)}
}

Invoke-RestMethod @Splat

到目前为止,我对任何 GET 调用都没有问题,只有 PUT 有问题。此外,如果我 运行 通过 ConvertTo-Json 传递的 Body 哈希表,输出看起来就像上面的工作示例。有没有人知道为什么这不起作用?

好的,所以我崩溃并安装了 Fiddler,我想我正在做点什么。 PowerShell cmdlet 似乎不知道如何处理 application/json 内容类型的数组。我不确定 XML 是否会出现这种情况,因为我还没有测试过。

我将主体更改为使用直 json 弦并且它有效:

$Body = "{ `"role_id_array`": [123456] }"

如果我使用哈希表并将值设置为这样的数组:

$Body = @{role_id_array = 115028,128732}

然后我会收到 400 失败响应。 Fiddler 向我展示了发生了什么——这是原始请求:

PUT https://api.us.onelogin.com/api/1/users/12345678/add_roles HTTP/1.1 授权:bearer:3c93ae2-编辑- 用户代理:Mozilla/5.0(Windows NT;Windows NT 6.3;en-US)WindowsPowerShell/5.1.14394.1000 内容类型:application/json 主持人:api.us.onelogin.com 内容长度:33 role_id_array=System.Object%5b%5d

请注意,数组未正确转换,Invoke-RestMethod 只是将其折叠成类型名称定义,类似于 Export-Csv 处理数组 属性 值的方式。

所以我认为我在使用 PUT 方法时遇到了问题,因为我的所有 GET 调用都在工作,但这是一个转移注意力的问题。真正的问题是处理一个 REST 端点,它需要数组值作为它的请求参数值。

编辑:我发现有人在 2014 年发布了这个问题,但他的解决方案是将 -ContentType 参数设置为 'application/json':

Powershell v4 Invoke-RestMethod body sends System.Object

我已经这样做了,但仍然遇到同样的问题。这是一个错误吗?

我能够 PUT 工作!

如何从 Invoke-RestMethod 获取丰富的错误响应数据

首先,我使用了 this blog post here,它有一个很好的方法来检索 Invoke-RestMethodWebRequest cmdlet 的完整错误消息。

在他的方法中,首先定义一个名为Failure的Function。

function Failure {
    $global:helpme = $body
    $global:helpmoref = $moref
    $global:result = $_.Exception.Response.GetResponseStream()
    $global:reader = New-Object System.IO.StreamReader($global:result)
    $global:responseBody = $global:reader.ReadToEnd();
    Write-Host -BackgroundColor:Black -ForegroundColor:Red "Status: A system exception was caught."
    Write-Host -BackgroundColor:Black -ForegroundColor:Red $global:responsebody
    Write-Host -BackgroundColor:Black -ForegroundColor:Red "The request body has been saved to `$global:helpme"
    break
}

然后,像这样将所有 Invoke-RestMethod 调用包装在一个 try Catch 块中。

try { 
    $e = Invoke-WebRequest 'https://api.us.onelogin.com/api/1/users/$id' `
        -Headers  @{ Authorization = "bearer:$token" } `
        -Body ( @{ phone = "7709746046" } | ConvertTo-Json ) `
        -Method Put `
        -ErrorAction:Stop `
        -ContentType 'application/json' 
} 
catch {Failure}

现在当您 运行 遇到错误时,您可以看到实际的消息,就像这样

> Status: A system exception was caught.
{"status":{"error":true,"code":400,"type":"bad request","message":{"description":"notes is not a valid attribute for user model","attribute":"notes"}}}
The request body has been saved to $global:helpme

这对帮助我摆脱遇到的错误非常有帮助,而且我能够使用 PUT 动词更新用户条目并使其正常工作。

正在解决您的问题

我只需要对您的代码进行两处更改即可使其正常工作。

首先,在 URI 周围加上引号,因为您的示例代码没有它们,您必须在哈希表中的字符串周围加上引号。

最后,将您的正文内容通过管道传输到 ConvertTo-JSON,否则数据将作为字符串发送,就像您在 Fiddler 中发现的那样。

经过这两项更改,这是我的请求和响应

$Splat = @{
    Method      = 'PUT'
    Uri         = 'https://api.us.onelogin.com/api/1/users/27697924/add_roles'
    ContentType = "application/json"
    Headers     = @{authorization = "bearer:$token" }
    Body        = @{role_id_array = @(143175)} | ConvertTo-Json
}

try {Invoke-RestMethod @Splat -ErrorAction Stop }
catch {Failure}

这是回复:

status                                                 
------                                                 
@{type=success; message=Success; error=False; code=200}

更新:我们做到了,现在已经修复了!

如果您认为 PowerShell 应该显示非 200 状态代码的实际服务器响应,请帮助提请注意 Github 上的这个 open issue on the PowerShell 项目页面。

添加您的反馈或竖起大拇指,我们可能会在该语言的未来版本中对此进行更改。

此问题现已从 PowerShell v6.1 开始修复