Operating System - Windows 10
Powershell version - 5.1.15063.1088
I'm using Windows PowerShell ISE (if that makes any sense). When running simple HTTP Post function
Function MyBeautifulFunction {
$myCredentials = Get-Credential
$body = #{
"query"="SELECT [System.Wheel],[System.SparkPlug],[System.EngineOil],[System.Headlight],[System.RadioButton] FROM JunkYard WHERE [System.Brand] = 'Ford' AND [System.Model] = 'GT' AND [System.Title] CONTAINS 'Rebuild'"
} | ConvertTo-Json
Invoke-RestMethod -Uri 'http://example.com//ford/parts/fuelpump/_apis/wit/wiql?api-version=2.0' `
-Method Post `
-Credential $myCredentials `
-Body $body `
-ContentType 'application/json'
}
MyBeautifulFunction
Editor's note: The Invoke-RestMethod call was originally spread across 2 lines without line continuation, which part of Adam's answer below discusses.
I'm getting following error message in PowerShell ISE console window:
"message":"The request indicated a Content-Type of \"application/x-www-form-urlencoded\" for method type \"POST\" which is not supported. Valid
content types for this method are: application/json, application/json-patch+json.
It's clearly visible that I'm passing 'application/json' in the parameter, but for some reason PowerShell still complains. Has anyone faced this error before? Should I report to Microsoft with it? Thanks for the advice...
Couple of things...
First, I call REST services all the time with a content type of application/json, and I don't have any problems. For example, the following works fine for me:
$url = 'https://jsonplaceholder.typicode.com/posts/1'
$response_from_webservice = Invoke-RestMethod -Uri $url -ContentType 'application/json' -Method 'Get'
jsonplaceholder... is a public service, available for testing. Feel free to run the snippet on your machine in-case you need a sanity check.
Second, this sample code you sent had this Accept parameter:
Invoke-RestMethod -Uri 'http://example.com//ford/parts/fuelpump/_apis/wit/wiql?api-version=2.0' -Method Post -Credential $myCredentials
-Body $body -ContentType 'application/json' -Accept 'application/json'
I don't believe I've seen that before. I am also running Windows 10 with Powershell v5.1.15063.1088. I've checked the docs. I checked out the commandlet's parameters. I didn't find it.
I share this to explain, I can't recreate your scenario with that call signature.
If you want to add an accept entry to the HTTP header, you'd have to do that directly:
$h = new-object 'system.collections.generic.dictionary[[string],[string]]'
$h.add('accept', 'application/json')
$r = Invoke-RestMethod -Uri '...' -ContentType 'application/json' -Method 'Post' -Headers $h
Third, it sort of looks like you're not specifying the content type in your snippet. The snippet has the Invoke-RestMethod on a seperate line from the body and contenttype parameters. Just to be clear, it's not wrapping. It looks like there is a line break there. That means that the second line -Body $body -ContentType 'application/json' -Accept 'application/json' is unassociated with the call that precedes it; the following is a copy and paste from your post:
Invoke-RestMethod -Uri 'http://example.com//ford/parts/fuelpump/_apis/wit/wiql?api-version=2.0' -Method Post -Credential $myCredentials
-Body $body -ContentType 'application/json' -Accept 'application/json'
If you want to put the parameters on a separate line, just use a backtick.
Invoke-RestMethod -Uri 'http://example.com//ford/parts/fuelpump/_apis/wit/wiql?api-version=2.0' `
-Method Post `
-Credential $myCredentials `
-Body $body `
-ContentType `
'application/json'
Now, if you don't specify the ContentType (as I'm suggesting) it will default to "application/x-www-form-urlencoded" on a post. According to Microsoft:
-ContentType
Specifies the content type of the web request.
If this parameter is omitted and the request method is POST,
Invoke-RestMethod sets the content type to
application/x-www-form-urlencoded. Otherwise, the content type is not
specified in the call.
You need to pass headers in to the headers argument
$headers = #{
"Content-Type" = "application/json",
"Accept" = "application/json"
}
Invoke-RestMethod -Uri 'http://example.com/123' -Method Post -Body $body -Headers $headers
See - https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod
Related
I have a web server that responds to a request https://localhost/GetUpdateInfo with a body [{"ipAddress": "10.200.2.55"}]
In postman its Work but in powershell i can`t do this because body begins from array.
When i do exmple code:
$Url = "https://localhost/GetUpdateInfo"
$Body = #(#{
ipAddress = "10.200.2.55"
})
$jsonBody = ConvertTo-Json -InputObject $Body
Invoke-RestMethod -Method 'Post' -Uri $url -Body $jsonBody
i hve error: Invoke-RestMethod : Block length does not match with its complement.
The content type of all POST requests is application/x-www-form-urlencoded unless specified.
Add -ContentType application/json to your last line call so your json is sent correctly.
Invoke-RestMethod -Method 'Post' -Uri $url -Body $jsonBody -ContentType 'application/json'
I need to add user permission when creating an environment through REST API with PowerShell.
I've looked at the network trace and this is the header when I tried to manually add a user permissions
Request URL:
https://dev.azure.com/{org}/_apis/securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/{project_id}_{env_id}
Request Method: Put
Request Body:
[{userId: "{id_of_user}", roleName: "Administrator"}]
And this is the code I tried:
# other code
...
$body = #(
#{ 'userId' = '{id_of_user}'; 'roleName': 'Administrator' }
) | ConvertTo-Json
Invoke-RestMethod -Uri $uri -Method Put -Body $body -ContentType "application/json" -Headers $header
But it is returning:
{"count":0,"value":{}}
The only missing thing is that in your body, you should provide an array instead of a single object, here is a working example:
$uri = "https://dev.azure.com/bauca/_apis/securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/{project_id}_{env_id}"
$id_of_user = 'YOUR_USER_ID'
$tokenbase = 'YOUR_PAT'
$header = #{
"authority"="dev.azure.com"
"Authorization"= "Basic $tokenbase"
"method"="PUT"
"path"="/{ORG}/_apis/securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/{project_id}_{env_id}"
"scheme"="https"
"accept"="application/json;api-version=5.0-preview.1;excludeUrls=true;enumsAsNumbers=true;msDateFormat=true;noArrayWrap=true"
"accept-encoding"="gzip, deflate, br"
"accept-language"="en-US,en;q=0.9,pt;q=0.8,nl;q=0.7"
"origin"="https://dev.azure.com"
"x-vss-reauthenticationaction"="Suppress"
} `
$body = "[{`"userId`":`"${id_of_user}`",`"roleName`":`"Administrator`"}]"
Invoke-RestMethod -UseBasicParsing -Uri $uri -Method "PUT" -Body $body -ContentType "application/json" -Headers $header
The returned results should be something like:
#{displayName=USER_NAME; id=USERID; uniqueName=USER_UNIQUENAME}
The API documentation is not clear about that, so, in this situations what I'd recommend you to do, is just use Chrome to do the requests through the UI, then inspect element and grab the network information of the request, after that 'Click with the right button' and then select 'Copy to Powershell' you'll see exactly what is the 'body' required to perform the request.
I am attempting to use Powershell to perform some "POST" requests. However, I can't seem to get the JSON correctly formatted. How do I accomplish this?
>> $JSON=#{name:"TestName"}
>> Invoke-WebRequest -Uri http://localhost:7071/api/HttpTrigger1 -Method POST -Body $JSON
>> $response = Invoke-WebRequest -Uri "http://localhost:7071/api/HttpTrigger1" -Method Post -Body $JSON -ContentType "application/json"
ParserError:
Line |
1 | $JSON=#{name:"TestName"}
| ~
| Missing '=' operator after key in hash literal.
So, there are two ways you can do this:
The first, as suggested by Santiago, is
$json = '{name:"TestName"}'
$response = Invoke-WebRequest -Uri "http://localhost:7071/api/HttpTrigger1" `
-Method Post -Body $json -ContentType "application/json"
The second, using (roughly) the syntax you were using, is
#create a Powershell object (note the use of '=' instead of ':' for assignment)
#(such a simple example is not an improvement over the example above)
$json = #{ name = "TestName" } | ConvertTo-JSON
$response = Invoke-WebRequest -Uri "http://localhost:7071/api/HttpTrigger1" `
-Method Post -Body $json -ContentType "application/json"
The first method is certainly cleaner and more direct. The second is useful when the source data for the request comes as the result of manipulating Powershell objects, and you want to convert them for use in a web request.
When using:
$body = #{
Manager = "spmigrationuser#contoso.com" #$item.PMEmail
Name = "some name"
Number = "Some number"
Practice = "Some Practice"
}
$response = Invoke-RestMethod -Method Post -Uri $Url -Body $body -ContentType 'application/json' # -Headers $Headers
Or
$response = Invoke-WebRequest -Method 'POST' -Uri $Url -Body $body -ContentType 'application/json' # -Headers $Headers
Neither ContentType 'application/json'
Nor
$Headers = #{'Content-Type' = 'application/json' }
-Headers $Headers
Works
The error is always:
"Invoke-WebRequest : {"error":{"code":"InvalidRequestContent","message":"The request content is not valid and could not be deserialized: 'Error parsing NaN value. Path '', line 1, position 1.'."}}"
The same call works in Postman
I am using PS 5.1 and I must have -ContentType 'application/json' otherwise PS works but the service fails
What can be the issue?
I agree with NickSalacious. Your issue is that you are not sending JSON.
If you are using Postman and just starting to do API in PowerShell. Postman has a "Code" Link in the top right hand corner of the request. Just below and to the right of the Send button. In there you can select PowerShell. This will give you a good basis to see how the same request could be ran in PowerShell.
Postman would turn your body into this:
$body = "{`n `"Manager`": `"spmigrationuser#contoso.com`",`n `"Name`": `"some name`",`n `"Number`": `"Some number`",`n `"Practice`": `"Some Practice`"`n}"
This is not the easiest to work with and to read. Learning and using ConvertTo-Json is going to help a lot more in the long run.
*Edit: Also look at Invoke-RestMethod and Invoke-WebRequest. They behave differently and sometimes one will be better than the other.
*Edit2: Figured I would put an example of another way to do it.
$request = #{
Uri = 'http://YourURI.Here'
Headers = #{ 'Authorization' = $token
'AnotherHeader?' = 'Sure'}
Method = 'POST'
Body = '{
"Manager": $item.PMEmail,
"Name": "some name",
"Number": "Some number",
"Practice": "Some Practice"
}'
ContentType = 'application/json'
}
$response = Invoke-RestMethod #request
The API requires that the body be a JSON string. You can do a simple conversion (using ConvertTo-Json) in your Invoke-RestMethod command and set the content type accordingly.
Invoke-RestMethod -Method POST -Uri $uri -Header $header -Body ($body | ConvertTo-Json) -ContentType 'application/json'
Sorry I bothered all of you.
I tested on another computer and it works fine.
I want to pass a few body parameters using x-www-form-urlencoded format using powershell invoke-restmethod. Do not that this is working fine in PostMan. My code for this is below but is not working. How do I accomplish this in powershell?
$param = [System.Web.HttpUtility]::UrlEncode("channel:channelID
Content-Type:application/x-www-form-urlencoded
limit:50")
$uri="https://MySlackWebsite.com/api/channels.history"
$test2 = Invoke-RestMethod -Method POST -Uri $uri -Headers $headerJson -Body $param
I got this to work with the following using the guidance I got from #Erik Kalkoken.
$headerJson = #{Authorization="Bearer xoxp-xyz"}
$postParams = #{channel='roomID';limit=50}
$uri="https://slackserver.com/api/channels.history"
Invoke-RestMethod -Method POST -Uri $uri -Headers $headerJson -Body $postParams -ContentType "application/x-www-form-urlencoded"
Here is an example script on how to retrieve the list of messages from a channel with a POST request.
$postParams = #{token='xoxp-XXX';channel='C12345678'}
$test2 = Invoke-WebRequest -Uri https://slack.com/api/channels.history -Method POST -Body $postParams
Write-Host $test2
It tested and based on this answer about how to create a POST request with PowerShell.