Powershell Invoke-Restmethod Can not use generated Authtoken as an variable - powershell

i´am trying to access a RESTAPI via Powershell.
Within the login process an Authtoken is generated and is needed for any later command and has to be put into the header. So far nothing special.
Of course i want to put the generated Authtoken into a variable for easier handling. But i´am unable to do so ...
Here is what i´am trying:
Logging in and getting the Authtoken
$payload = #{"login"="username";"password"="password"}
$AuthToken = Invoke-RestMethod -Method Post -ContentType application/json -Body (ConvertTo-Json $payload) -Uri "https://path/to/api/login"
Because the API accepts the authoken only in a special form i have to edit it a little bit
$AuthToken = $AuthToken.Replace("auth_token=",'"auth_token"="')
$AuthToken = $AuthToken.Insert(73,‚"‘)
The Authtoken before
#{auth_token=rShln/Yc2cepDtzbNFntdZue:9c3ce025e5485b14090ca25500f15fa2}
and after my Treatment
#{"auth_token"="St6tecwEseAQegkfhACXUwaj:d7e3e2095ba31073e3fbc043c4563d28"}
If i manually insert the Authtoken into the Restmethod the call looks this:
Invoke-RestMethod -Method Get -ContentType application/json -Headers #{"auth_token"="JsRaTBRlElpq1jLLX5z3TXUy:91d0e1eee1943f6cd6dbaa1d0b9ba9d0"} -Uri "https://path/to/api/something"
As you may gues this works pretty well! If i now try use the Authtoken from my variable my Rest Call looks like this:
Invoke-RestMethod -Method Get -ContentType application/json -Headers $Authtoken -Uri "https://path/to/api/something"
Powershell gives me the following error
Invoke-RestMethod : Cannot bind parameter 'Headers'. Cannot convert the "#{"auth_token"="St6tecwEseAQegkfhACXUwaj:d7e3e2095ba31073e3fbc043c4563d28"}" value of type "System.String" to type
"System.Collections.IDictionary".
At C:\Users\User\Desktop\xxx.ps1:6 char:70
+ ... -Method Get -ContentType application/json -Headers $AuthToken -Uri "h ...
+ ~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-RestMethod], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I have no clue why i´am getting this error and would be so thankfull i someone could help me out on this!

I had this issue when using airtable api.
what i did was just curl "https://api.airtable.com/v0/app----/Post?maxRecords=3&view=Grid%20view" -H #{"Authorization" = "Bearer Your-Api-here"}
And it worked
Iam a newbie here, i just post this here thinking it might help someone, it took me hours to discover this.

So right now it looks like $AuthToken is a string. The string is formatted like you would expect a Hashtable to be, but I don't think it's actually a hashtable. What you can do to fix this is to use Invoke-Expression on the string, and that will convert it to an actual hashtable for you. Something like:
$AuthToken = Invoke-Expression $AuthToken
Invoke-RestMethod -Method Get -ContentType application/json -Headers $Authtoken -Uri "https://path/to/api/something"

The Header should be in System.Collections.IDictionary method (check : https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.system-collections-idictionary-add?view=netframework-4.8)
Example: Am doing it on a centreon api
The header Variable should be: $headers = #{"centreon-auth-token" = "$Key"}
The key contain only the token, example: NWU5ZDY5ODFiNWI2YTYuMzAzNjM3NDI=

Looks like this is an insane PowerShell bug. If you have a tab after -Header $Headers, the casting to Collections.IDictionary fails because the tab is removed somewhere inside.
I'll raise an issue on Github.
Solution is to make sure that there are no tabs between your parameters. They may look the same
Issue raised in PWSH github:
https://github.com/PowerShell/PowerShell/issues/15943

Had a similar issue while trying to run through a tutorial for building APIs with Python (Auth0).
Was able to create a work around by putting the commands into a .sh file, and ran that. Worked running the file.
#James Lear appears the bug is still there

Related

Uploading a text file to discord using webhook

I looked through and tested a few examples I saw online with no success.
From what I understand it should look something like the code below:
$hookUrl = 'https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXXXXX'
$Body = #{
'username' = $env:username
'content' = "this is a test"
"file=#C:\Users\User\Desktop\test.txt"
}
Invoke-WebRequest -uri $hookUrl -Method POST -Body $Body -Headers #{'Content-Type' = 'application/json'}
ERRORS
Invoke-WebRequest : {"code": 50109, "message": "The request body contains invalid JSON."}
At line:11 char:1
+ Invoke-WebRequest -uri $hookUrl -Method POST -Body $Body -Headers #{' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
I have seen a few extensively long methods to achieve this in the documentation, however if you see below I will post a one liner that accomplishes what I want using CMD. Is it really this simple in CMD but in powershell it takes 15+ lines?
curl -F "payload_json={\"username\": \"jakoby\", \"content\": \"download me\"}" -F "file=#\"C:\Users\User\Desktop\newUser.txt\"" WEB-HOOK
Update:
The answer below (next section) addresses the original form of your question.
It later emerged that you're looking for the PowerShell equivalent of a curl command line that uses a multipart/form-data submission to submit both JSON and upload a local file.
Example 6 in the Invoke-WebRequest help topic shows you how to do that, but it is more verbose than the curl command.
The simplest solution may therefore be to simply call your curl command from PowerShell, but be sure to use curl.exe to unambiguously target the external executable, not the curl alias for Invoke-WebRequest that is built into Windows PowerShell (it has been removed in PowerShell (Core) 7+).
curl.exe -F "payload_json={\`"username\`": \`"jakoby\`", \`"content\`": \`"download me\`"}" -F "file=#\`"C:\Users\User\Desktop\newUser.txt\`"" WEB-HOOK
Note the unfortunate need to escape the embedded " twice:
Once, with `, to satisfy PowerShell's syntax requirements for double-quoted strings (as expected).
You could obviate the need for this if you used '...' for the overall quoting, but that would preclude embedding variable values directly in the string.
Unexpectedly again, with \, to work around a long-standing bug with respect to passing arguments containing verbatim " chars. to external programs, still present as of PowerShell 7.2.x - see this answer.
Since the target web service expects JSON, you must convert your $Body hashtable to JSON before passing it to Invoke-WebRequest's -Body parameter, which you can do with ConvertTo-Json:
Invoke-WebRequest -uri $hookUrl -Method POST -Body (ConvertTo-Json $Body) -Headers #{'Content-Type' = 'application/json'}
The obligatory general caveat: with more deeply nested objects, you may need to pass a -Depth argument to ConvertTo-Json to prevent accidental truncation of data - see this post.
It seems that you also want to upload a local file:
Since the web service has no access to your local file system, passing a local file path as part of your JSON cannot work - the local file's content must be uploaded.
The Invoke-WebRequest docs only discuss uploading local files in the context of multipart/form-data submissions - see example 6, for instance.

Cant' Access API with Powershell but can access using Postman, Python, or cURL

I'm trying to get data back from an API online using Powershell with the command Invoke-WebRequest -UseBasicParsing $request_string -Method Get -Headers $headers) but am getting back Invoke-WebRequest : The remote server returned an error: (403) Forbidden.
I am supplying a $headers dictionary. Strangely, I can access the API using Postman, Python, and cURL. It's only when using Powershell commands that I get the 403 error. In fact, I used Postman's Code Snippet feature to generate my Powershell code, and it still doensn't work! Postman's Powershell Code Snippet was:
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Bearer {removed for security}")
$response = Invoke-RestMethod '{removed for security}' -Method 'GET' -Headers $headers
$response | ConvertTo-Json
To recap, both Invoke-WebRequest and Invoke-RestMethod don't work.
Any help here is much appreciated.
Thanks!
Figured it out on my own.
The API vendor enforced https requirement instead of just http. Apparently, Postman, Python, and cURL can figure that out on their own and change the request accordingly, but Powershell cannot.

Powershell equivalent to curl -F to upload a file

I need to upload files via commandline / powershell.
It works fine with
curl -F "file=#test.txt" https://api.anonfiles.com/upload
However, curl does not exist on Windows Server 2016 and I do not want to tell my clients to set it up. So I am looking for a powershell alternative to accomplish this task. I tried various solutions, but none of them worked. What I tried so far:
(1)
$postParams = #{file='C:\users\user\testfile.txt'}; Invoke-WebRequest -Uri https://api.anonfiles.com/upload -Method POST -Body $postParams
(2)
Invoke-WebRequest -UseBasicParsing https://api.anonfiles.com/upload -ContentType "application/json" -Method POST -InFile "C:\users\user\testfile.txt"
(3)
$file=[io.file]::readallbytes('c:\users\user\testfile.txt')
Invoke-WebRequest -UseBasicParsing https://api.anonfiles.com/upload -ContentType "application/json" -Method POST -Body "{ '#file':'"$file"'}"
None of it works. I canot believe it's so hard to replace an curl oneliner in powershell... The error in each case is a 400 http error, the request is wrong.
How do I send the above mentioned curl-request equivalent in powershell? The site is https://anonfiles.com/docs/api
I gave up. It's not possible in Powershell.
My App will just download curl.exe as standalone from now on, if it's not there.

Weird behavior while invoking Rest call using Invoke-RestMethod on Powershell script

I want to pass body(parameters) to Rest-call using Invoke-RestMethod(powershell script) in GET call. but I think it's not supported because of some security reasons(some RFC standards).
But in single session, When I first use POST method and then if I use GET method then it works. but if I directly call get method then it's throwing below error.
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send
So, Is there some information powershell stores after first call ? Also, Is there any way to pass parameters to "GET" Restcall in powershell script ?
I've attached code snippet:
this snippet is working.
Invoke-RestMethod 'https://test_url/url_path?param1=par' -Method 'POST' -Headers $headers
Invoke-RestMethod 'https://test_url/url_path?param1=par' -Method 'GET' -Headers $headers # works
but this throws the error,
Invoke-RestMethod 'https://test_url/url_path?param1=par' -Method 'GET' -Headers $headers #Not works

Powershell Invoke-Webrequest post method - incorrect payload length

I am trying to submit a form using invoke-webrequst cmdlet, and this is the code
$postParams = #{regno='1234567';dob='01/01/1997';B1='Get Marks'}
$response = Invoke-Webrequest -Uri ("http://studentresulsts/res.asp") -Body $postParams -Method Post -Debug -OutFile out.html
VERBOSE: POST http://studentresulsts/res.asp with -1-byte payload
VERBOSE: received 13-byte response of content type text/html
The $response comes back as 'Access Denied' (13-byte response)
The payload length is shown as 1-byte while $postParams is clearly more than that. Wondering if that's the reason I am getting 'Access Denied'.
Checked the form manually in browser and it works fine with correct field values.
I am using powershell 4.0
Answer : Okay, I was missing referrer URL in the header which the server was looking for, then I included referrer and it works fine :) . My new script looks like this. Thanks for your help...
$postParams = #{regno='1234567';dob='01/01/1997';B1='Get Marks'}
$headervals = #{'Referer'='http://studentresulsts/gdslplus/gdslform.htm';'Content-Type'='application/x-www-form-urlencoded'}
$response = Invoke-Webrequest -Uri ("http://studentresulsts/res.asp") -Body $postParams -Method Post -Debug -OutFile out.html
The fact that you don't have to manually authenticate does not mean the access isn't verified(e.g. trusted sites in IE).
Perhaps you are missing a crucial header?