Invoke-WebRequest : Cannot bind parameter 'Headers' - powershell

I am trying to execute a curl command in powershell:
curl --user bitcoinipvision --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "move", "params": ["acc-1", "acc-2", 6, 5, "happy birthday!"] }' -H 'content-type: application/json;' http://localhost:18332/
But I get this error, what is the problem?
Invoke-WebRequest : Cannot bind parameter 'Headers'. Cannot convert the
"content-type: application/json;" value of type "System.String" to type
"System.Collections.IDictionary".
At line:1 char:158
+ ... 5, "happy birthday!"] }' -H 'content-type: application/json;' http:// ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-WebRequest], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

As already stated out by some commenters you will see that curl is actually just an alias to Invoke-WebRequest:
PS> Get-Command curl
CommandType Name Version Source
----------- ---- ------- ------
Alias curl -> Invoke-WebRequest
Note: I suggest to use Get-Command, not Get-Alias because you maybe don't know if the command you are using is an alias, cmdlet, or an executable.
From this point there are two possible ways to solve your issue:
Use PowerShell's Invoke-RestMethod (or, if you are using PowerShell < 3, Invoke-WebRequest):
Invoke-RestMethod -Uri http://localhost:18332/ -Credential bitcoinipvision -body $thisCanBeAPowerShellObject
As you can see, no content-type is needed as JSON is IRM's default content Type; though you can change it using -ContentType.
If available in your current environment, use the original cUrl. You have to type it this way:
curl.exe --user bitcoinipvision --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "move", "params": ["acc-1", "acc-2", 6, 5, "happy birthday!"] }' -H 'content-type: application/json;' http://localhost:18332/
I would definitely prefer the first one over the 2nd one, as PowerShell natively supports JSON answers, which allows you to easily use them, e.g. by piping it to Where-Object, Format-Table, Select-Object, Measure-Object and so much mure. If you prefer to use cUrl, you have to parse the String returned by the curl.exe process on your own. This could also be problematic with binary content.

Curl basically uses Invoke-Webrequest in PowerShell.
As you can see in the error, the header basically accepts the form "System.Collections.IDictionary"n and you are passing through a "System.String".
Converting the Header to a dictionary/hashtable would resolve the issue,
curl --user bitcoinipvision --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "move", "params": ["acc-1", "acc-2", 6, 5, "happy birthday!"] }' -H #{ "content-type" = "application/json"} http://localhost:18332/

I had a similar issue, until i found this:
https://github.com/MicrosoftDocs/azure-docs/issues/31851
"The commands are designed to be ran within the specific VM and in a Bash environment. Not in PowerShell. So the error you see would be expected in most cases."

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.

Using GET in PowerShell & Exporting JSON to CSV

I'm using the following CURL command, to read/fetch table data from an API:
curl -X GET \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer *myAccessToken*' \
https://www.myWebsite.com/api/orders
This command/API Call returns a table in JSON format. I need to do two things with this.
[1] I need to run this in powershell. I've tried using the above code, and returns a general syntax error:
A parameter cannot be found that matches parameter name 'X'.
[2] In PowerShell, Have the JSON output converted & saved as a CSV file
Any ideas? Thanks!
You can use Invoke-RestMethod Cmdlet to Sends an HTTP or HTTPS request to a RESTful web service.
$uri = "https://www.myWebsite.com/api/orders"
$headers = #{
'Content-Type' = 'application/json'
'Authorization' = 'Bearer <AccessToken>'
'Accept'= 'application/json'
}
$response = Invoke-RestMethod -Uri $uri -Method GET -Headers $headers
PowerShell formats the response based to the data type. For JavaScript Object Notation (JSON) or XML, PowerShell converts, or deserializes, the content into [PSCustomObject] objects. So you can select the columns you want to export and pipe it into Export-Csv Cmdlet
$response | Select ColumnName1,ColumnName2 | Export-Csv -Path "filename.csv" -NoTypeInformation

Convert sed command from cUrl to Powershell

I'm trying to convert the commands from How to redeploy instance using API in rancher to powershell.
pod_upgrade_body=$(curl -u "token-[use your token here]" \
-s 'https://rancher.mydomain.com/v3/project/c-zqpm5:p-h884r/workloads/deployment:development:api' \
-X GET \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Pragma: no-cache' \
-H 'Cache-Control: no-cache' 2>&1 | sed "s/\"cattle\.io\/timestamp\"\:\"[0-9T:Z-]*\"/\"cattle\.io\/timestamp\":\"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"/g")
This is my attempt but I can't seem to make it work
Invoke-WebRequest -Method GET -Uri https://rancher... -Header #{Accept = 'application/json'; Authorization = 'Bearer [my-token]'; 'Content-type' = 'application/json'; Pragma = 'no-cache'; 'Cache-Control' = 'no-cache'} |cat %{$_ -replace "s/\`"cattle.io/timestamp\`":\`"[0-9T:Z-]*\`"/\`"cattle.io/timestamp","$(date -u +"%Y-%m-%dT%H:%M:%SZ")\`"/g"}
I'm getting the following error
Get-Content : A positional parameter cannot be found that accepts argument '$_ -replace "s/\`"cattle.io/timestamp\`":\`"[0-9T:Z-]*\`"/\`"cattle.io/timestamp","$(date -u
+"%Y-%m-%dT%H:%M:%SZ")\`"/g"'.
Since you're receiving JSON data, it is better to use Invoke-RestMethod than Invoke-WebRequest.
Doing so means that the JSON response is automatically parsed into a [pscustomobject] object graph that allows direct OO access to the data returned for easy, dot-notation-based querying and updating.
You can can re-convert to JSON using ConvertTo-Json (beware the default serialization depth of just 2: use -Depth as needed).
To put it all together:
$fromJson =
Invoke-RestMethod -Method GET -Uri https://rancher... -Headers #{Accept = 'application/json'; Authorization = 'Bearer [my-token]'; 'Content-type' = 'application/json'; Pragma = 'no-cache'; 'Cache-Control' = 'no-cache' } |
ForEach-Object {
$_.annotations.'cattle.io/timestamp' = Get-Date ([datetime]::UtcNow) -UFormat '%Y-%m-%dT%H:%M:%SZ'
}
# Re-convert to JSON, if needed.
# Adjust -Depth as needed.
$fromJson | ConvertTo-Json -Depth 5
Note: I'm assuming that the cattle.io/timestamp properties are inside annotations property, based on the forum link in your question.
As for what you tried:
In Windows PowerShell (but not PowerShell (Core) 7+), cat is a built in alias for Get-Content, which reads text files specified by their paths - it doesn't support receiving data via the pipeline, the way that cat Unix utility does.
However, there is no need for such a utility; the use of the ForEach-Object cmdlet, whose built-in alias % you tried to use, by itself is sufficient to process each input object via the script block ({ ... }) passed to it, inside of which the automatic $_ variable refers to the input object at hand.
The translation of the sed command into a -replace operation has several problems:
-replace doesn't support sed functions such as s - it is the s (string substitution) function in a manner of speaking.
The search regex and the replacement string must be passed as separate arguments (and each must not be enclosed in /.../ delimiters).
-replace doesn't support options (other than inline regex option in the regex operand), and it invariably replaces all occurrences; that is, sed's /g option is implied.
The external date utility is only available on Unix-like platforms by default; PowerShell's equivalent is the Get-Date cmdlet, as shown above.

How to pipe wget results to subsequent curl post?

I am in Windows 10 attempting to get Confluent CE up via docker. See their instructions here.
The trouble is I believe these are specifically for MAC OS, and Windows requires slightly different syntax for the following command:
wget https://github.com/confluentinc/kafka-connect-datagen/raw/master/config/connector_pageviews_cos.config
curl -X POST -H "Content-Type: application/json" --data #connector_pageviews_cos.config http://localhost:8083/connectors
I think I am supposed to be piping the wget results to the curl. How to do that in Windows 10 ?
The powershell exception:
At line:1 char:57
+ ... ntent-Type: application/json" --data #connector_pageviews_cos.config ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~
The splatting operator '#' cannot be used to reference variables in an expression. '#connector_pageviews_cos' can be
used only as an argument to a command. To reference variables in an expression use '$connector_pageviews_cos'.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : SplattingNotPermitted
Thanks!
Both curl and wget are aliased in Powershell 5.1 to Invoke-WebRequest, although it seems that curl.exe is available under System32 (and is available in place of an alias in Powershell Core). But, it's not too difficult to translate both calls to the Powershell-native Invoke-WebRequest cmdlet.
Your wget call becomes:
Invoke-WebRequest -Uri https://github.com/confluentinc/kafka-connect-datagen/raw/master/config/connector_pageviews_cos.config -Outfile connector_pageviews_cos.config
And your curl call becomes:
Invoke-WebRequest -Uri http://localhost:8083/connectors -Method POST -ContentType 'application/json' -Body (Get-Content -Raw connector_pageviews_cos.config)
If desired, you can combine both calls into a single line, as the -Body parameter accepts pipeline input:
Invoke-WebRequest -Uri https://github.com/confluentinc/kafka-connect-datagen/raw/master/config/connector_pageviews_cos.config |
Invoke-WebRequest -Uri http://localhost:8083/connectors -Method POST -ContentType 'application/json'
Omit the -OutFile parameter on the first Invoke-WebRequest, which outputs the payload contents to the pipeline. You then pipe that output into the second Invoke-WebRequest while providing other positional and named arguments as needed.
More information on Invoke-WebRequest is available here, and you would also do well to check out the convenient-to-use Invoke-RestMethod which makes working with RESTful APIs much more comfortable.
As a note, the # operator is used for a concept called splatting in Powershell, which explains the error you were receiving. Read the link above for more information, and elsewhere I've also written an answer on how to use splatting to pass arguments to cmdlets and commands.

How do I upload an attachment to a JIRA issue via powershell?

I have been searching online for a while and I've not found a solid answer to this (lots of partial answers, though). Still nothing I do works.
I'm trying to write a powershell script to send attachments to JIRA using cURL (have not found another way that I can get to work).
My cURL command is:
C:\opt\curl\curl.exe -u user:pa$$word -X POST -H "X-Atlassian-Token: nocheck" -F "file=#C:\opt\attachments\75391_testingPNG.png" http://jira.ourURL.com/rest/api/2/issue/75391/attachments
This works perfectly from the command line. Anytime I try to run it via powershell it bombs out. Seems like it should be very easy to do, though. Just want to grab the files from a directory and send them to JIRA.
Anyone have any thoughts about this??? Thanks!
I suspect that the characters $ and # in the arguments could be causing you problems (In case that is what you are using). Try escaping them using the backtick symbol.
To start curl.exe using the specified parameters, try the following command:
Start-Process C:\opt\curl\curl.exe -argumentList "-u", "user:pa`$`$Word", "-X", "POST", "-H", "`"X-Atlassian-Token: nocheck`"", "-F", "`"file=`#C:\opt\attachments\75391_testingPNG.png`"", "http://jira.ourURL.com/rest/api/2/issue/75391/attachments"
Basically it means that where you would separate arguments with a space in a command prompt, you would send each argument as an element in a powershell string Array and use it as the value in the -argumentlist parameter to Start-Process.
If you're using PowerShell 3+, you can use the native method Invoke-RestMethod to talk to JIRA, and not have to worry about escaping characters to shell out to a command:
# Build a basic auth header:
$headers = #{
'Authorization' = "Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $UserName, $Password))))"
'X-Atlassian-Token' = 'nocheck'
}
Invoke-RestMethod -Uri "http://jira.ourURL.com/rest/api/2/issue/75391/attachments" -Method Post -InFile "C:\opt\attachments\75391_testingPNG.png" -ContentType "multipart/form-data" -Headers $headers
I'm actually not sure what the nocheck header you're adding does though; I've not needed it when talking to JIRA over REST.