Bad request when calling rest api using curl or Invoke-RestMethod - powershell

I want to convert speech to text using Microsoft speech-to-text service from within a bash script or PowerShell script. I tried using curl (Git bash) and Invoke-RestMethod (PowerShell) to send my 16 bit pcm mono wav audio file to the stt service.
The service is working, I used a c# example provided by Microsoft to test it. With the c# example I'm able to send the audio file and receive the text from the stt services.
Now I wanted to do this in a script.
Using curl in Git Bash:
curl -X POST "https://westus.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=en-US&format=detailed" \
-H "Ocp-Apim-Subscription-Key: <my_subscription_key>" \
-H "Content-Type: audio/wav; codecs=audio/pcm; samplerate=16000" \
--data-binary audio.wav
Insufficient data to detect audio format: 7 bytes
Even using -d or --data or --data-raw instead of --data-binary doesn't change anything.
Using Invoke-RestMethod in PowerShell:
$audioBytes = [System.IO.File]::ReadAllBytes("c:\full\path\to\aduio\file.wav")
Invoke-RestMethod `
-Method Post `
-Uri "https://westeurope.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=en-US&format=detailed" `
-Headers #{'Ocp-Apim-Subscription-Key' = '<my_subscription_key>'} `
-ContentType 'audio/wav; codecs=audio/pcm; samplerate=16000' `
-Body $audioBytes
Invoke-RestMethod: The remote server returned an error: (400) Bad Request.
Same error using -InFile audio.wav instead of -Body $audioBytes.
Am I missing something? Is there an error which I don't see?

Related

Convert Powershell command to curl

I am trying make the following API calls with a curl command and run it on Linux:
https://octopus.com/blog/manually-push-build-information-to-octopus
This what I got:
curl -X POST https://YourServerUrl -H "X-Octopus-ApiKey"="API-XXXXXXXXXXXXXXXXXXXXXXXXXX" -H "Content-Type: application/json" -d "#jsonBody"
I am not sure how to convert this script to a json in curl
$jsonBody = #{
PackageId = "twerthi/xCertificatePermission"
Version = "1.0.0"
OctopusBuildInformation =
#{
BuildEnvironment = "Jenkins"
VcsCommitNumber = "2350881a389517288b31432d469c5c4199a1fba9"
VcsType = "Git"
VcsRoot = "https://github.com/twerthi/xCertificatePermission.git"
}
} | ConvertTo-Json -Depth 10
The curl command -d (--data) is the specified data in the POST request. So you should be able to just enter valid JSON data as part of the call. i.e. something like this:
curl -X POST https://YourServerUrl -H "X-Octopus-ApiKey"="API-XXX" -H "Content-Type: application/json" -d '{ "PackageId":"twerthi/xCertificatePermission", "Version":"1.0.0", "OctopusBuildInformation":{ "BuildEnvironment":"Jenkins", "VcsCommitNumber":"2350881a389517288b31432d469c5c4199a1fba9", "VcsType":"Git", "VcsRoot":"https://github.com/twerthi/xCertificatePermission.git"}}'
Note, if you are testing this in cmd/bash etc, you can split the command over multiple lines by using an escape character. Windows: ^ Linux/MacOS: \
Example in Windows:
curl -X POST https://YourServerUrl ^
-H "X-Octopus-ApiKey"="API-XXX" ^
etc....
Also, assuming that's valid PS, you can just run it and check the result in $jsonBody to see how its formatted.
Assuming you want to call the external curl utility from PowerShell (note that on Windows, in Windows PowerShell, you'll have to call it as curl.exe):
curl -X POST https://YourServerUrl `
-H 'X-Octopus-ApiKey: API-XXXXXXXXXXXXXXXXXXXXXXXXXX' `
-H 'Content-Type: application/json' `
-d ($jsonBody -replace '([\\]*)"', '$1$1\"')
Note the unfortunate need for a -replace operation on the $jsonBody variable containing your JSON string, which - as of PowerShell 7.1 - is needed to work around a long-standing bug, discussed in this answer.

Remote server Run CMD in Powershell

I am trying to upload a Zip file via RestAPI in powershell and Powershell version I am using is 5.1.
since Invoke-restmethod in powershell 5.1 doesn't have -form option,I tried to run curl command in CMD using powershell.When I run it locally it's working correctly. But when i try to run it in a server(azure devops agent) I am getting error saying curl command is not recognized.
What am i missing here it's runs as expected when i try in vs code, but not when i run it from a server.
$header1 = "accept: application/json"
$header2 = "X-Authorization: $($token)"
$header3 = "Content-Type: multipart/form-data"
$body1 = "upload=#Name.zip;type=application/x-zip-compressed"
$body2 = "actionIfExisting=Existing"
$body3 = "publicWorkspace=Public"
cmd.exe /c curl -X POST $uri -H $header1 -H $header2 -H $header3 -F $body1 -F $body2 -F $body3
Luckily I had git installed in the server and I read in this stack overflow page that Git comes with preInstalled curl.exe. So I called the path where git has curl.exe and using & operator in powershell to execute the curl.exe directly in powershell itself.
& 'C:\users\git\mingw64\bin\curl.exe' -X POST $uri -H $header1 -H $header2 -H $header3 -F $body1 -F $body2 -F $body3

Upload a file to an API using Powershell

I am trying to post a file to an API, which works perfectly under Linux using this curl command:
curl -X POST --header 'Content-Type: multipart/form-data' --header 'Accept: application/json' --header 'Authorization: Token foo_bar' -F content=#'Filename.ending' 'http://test.test.com/api/upload'
I don't get how to work with the 'F' Parameter in curl on the Invoke-RestMethod/Invoke-WebRequest command. I tried:
Invoke-WebRequest -Uri $URL -Headers #{Authorization = 'Token '+foo_bar} -Method POST -ContentType 'multipart/form-data'
I tried adding -F 'C:\Users\Me\Filename.ending' to my command, I also tried using -InFile 'C:\Users\Me\Filename.ending', but I always get a response from the API telling me:
{"error":{"code":"GENERAL_ERROR","message":"missing uploaded file 'Filename.ending'"}}
Which probably suggests it wants the file in a different way. I also tried reading it in by Get-Content 'C:\Users\Me\Filename.ending' but had no success. What am I missing?

Passing API key with HTTP header in cURL

I have an API Proxy in Apigee which is authenticated with an API key. I'm passing the key with my HTTP request header using cURL, with this command:
curl -v -H "apikey: my_key" http://api_org-test.apigee.net/v1/helloapikey
I get this error:
Invoke-WebRequest : Cannot bind parameter 'Headers'. Cannot convert the
"apikey: my_key" value of type "System.String" to
type "System.Collections.IDictionary".
When I modify my policy to look for the key in query parameter rather than the header, it works fine. Am I missing something here?
Try this:
curl -v -H #{'apikey' = 'my_key'} http://api_org-test.apigee.net/v1/helloapikey
Note:
curl is an alias for the Invoke-WebRequest cmdlet:
Get-Alias curl
output:
CommandType Name
----------- ----
Alias curl -> Invoke-WebRequest
You could install curl:
https://stackoverflow.com/a/16216825/3013633
Remove existing curl alias by executing this command:
Remove-item alias:curl
Then your command will work:
curl -v -H "apikey: my_key" http://api_org-test.apigee.net/v1/helloapikey
None of the above answers worked for me (I got an error -- parse error near }).
This worked:
curl -X GET \
'http://api_org-test.apigee.net/v1/helloapikey' \
-H 'apikey: my_key'
PowerShell simply does not resolve the variable within your URL. You are trying to query the service at the URI http://$serverHost:1234/service which won't work. You could do
$serverHost = "myHost"
$service = "http://$serverHost`:1234/service"
Invoke-WebRequest $service -Method Get
Just to add this to the discussion, I had to both hash the api key, but leave the token call key phrase rather than change it to 'apikey'. That's just what worked for me!
curl -v -H #{'X-API-TOKEN' = '[*insert key here*]'} '*datacenter_url*)'
Also noteworthy to PowerShell newcomers, -v stands for verbose. This switch gives you a Cyan-colored text under the command in PowerShell ise about the command PS is running. Almost like a play-by-play commentary. Useful enough I thought I'd mention it.

Replicating curl POST with Invoke-RestMethod in PowerShell

I'm trying to replicate the following curl command in PowerShell:
linguist#qa:~ % curl -X POST -F text="Example lesson text" -F share_status=private \
-F title="Example Lesson Ttiel" -F collection=50510 \
-F image=#/home/lingq/Pictures/penguin.jpg \
-F tags=British -F tags=European
'https://www.lingq.com/api/languages/en/lessons/' -H 'Authorization: Token bd894eabcd4c0'
This is an API usage example from their page, I'm working with the assumption that it works. I don't know if it actually does, I don't have curl, and I don't want to have curl if possible.
I've been trying to recreate the command in PowerShell using the InvokeRestMethod function. So far what I got is this:
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization","Token db3403c339fb4515c2940cccdcdcdbdcdbdcdbddc4cf453534453")
$response = Invoke-RestMethod -Method Post 'https://www.lingq.com/api/languages/ja/lessons/' -Headers $headers
I'm not even sure I'm adding the header with the token correctly, and I have no idea how to add the parameters that follow the -F in curl. I don't need image and tags, but the rest are crucial. Any ideas?
Edit: I have verified that the authentication token header works, by calling
Invoke-RestMethod -Method Get 'https://www.lingq.com/api/profile/' -Headers $headers
with my token and getting my profile.
I've also found out what the ominous -F means in curl, it's form data. So now I'm trying to figure out how to send 4 form data values in one Invoke-RestMethod call.
There is a similar question with this answer that should help you out. If you are having trouble with what the curl switches mean, you don't have to install it to look up its documentation.