I was able to get a PUT
to work!
How to get rich error response data from Invoke-RestMethod
First, I used this blog post here which has an excellent method to retrieve the full error message of an Invoke-RestMethod
or WebRequest
cmdlet.
In his method, first define a Function called Failure.
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
}
Then, wrap all of your Invoke-RestMethod calls in a try Catch block like this.
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}
Now when you run into an error, you can see the actual message, like this
> 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
This was super helpful in helping me get rid of the errors I was encountering, and I was able to update a user entry using a PUT
verb and get it to work.
Fixing your issue
I only had to make two changes to your code to get this to work.
First, put quotes around the URI, as your example code didn't have them and you must have quotes around strings in a hashtable.
Finally, pipe your body content to ConvertTo-JSON
, otherwise the data is sent over as a string, as you found in Fiddler.
With those two changes, here's my request and the response
$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}
Here's the response:
status
------
@{type=success; message=Success; error=False; code=200}
Update: we did it, this has now been fixed!
If you think PowerShell should present the actual server response for a non 200 status code, then help draw attention to this open issue on the PowerShell project page on Github.
Add your feedback or thumbs up it, and we might be able to get this changed in a future release of the language.
This issue is now fixed as of PowerShell v6.1
body
to JSON ahead of time. I'm not certain that Invoke-RestMethod will automatically convert the Body payload to JSON. I've had to do this for other REST endpoints before. To be clear, you'd run$Body = @{role_id_array = @(123456)} | ConvertTo-JSON
in it's own line, and then provide that as a separate param, or within your splat. – FoxDeploy