Equivalent curl -F in PowerShell Invoke-webrequest - powershell

I'm trying to find the equivalent of this curl command in PowerShell with Invoke-webrequest :
curl -k https://url/api \
-H "Authorization: mykey" \
-F "json=#test.json;type=application/json" \
-F "file=#test.txt; type=application/octet-stream"```
-H is ok, but I didn't find for two -F option.
Any idea ?
Many thanks.

The -f switch in cUrl is used for a multi-part formdata content type. PowerShell fortunately natively supports it, here's a generic example to get you started.
$Uri = 'https://api.contoso.com/v2/profile'
$Form = #{
firstName = 'John'
lastName = 'Doe'
email = 'john.doe#contoso.com'
avatar = Get-Item -Path 'c:\Pictures\jdoe.png'
birthday = '1980-10-15'
hobbies = 'Hiking','Fishing','Jogging'
}
$Result = Invoke-WebRequest -Uri $Uri -Method Post -Form $Form
And for your specific scenario, something like this should get you moving in the right direction.
$url = 'https://url/api'
$Form = #{
json = Get-Content .\test.json
file = Get-Content .\test.txt
}
$Result = Invoke-WebRequest -Uri $Uri -Method Post -Form $Form -Token "mkey"

It seems like you should be able to do -Form ... -Form ... but you can't, you need to build a multipart form object to submit.
see example 5 of the Microsoft docs https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-7.1
or this https://stackoverflow.com/a/65093133/89584 answer
or just install curl on windows (https://stackoverflow.com/a/16216825/89584) and use curl's nicer API

Related

Powershell Invoke-RestMethod set form field data type like cURL

I am using Powershell 7.3.1 and Invoke-RestMethod. I need to submit a form to a server but one of the fields needs to be typed as JSON or the request will fail. In cURL, this can be accomplished by appending ;type=application/json to the field but that doesn't seem to work with Invoke-RestMethod.
In cURL, submitting a form with types would look something like this:
curl --location --request POST 'http://localhost:8082/csv-as-input' \
--header 'Content-Type: multipart/form-data' \
--form 'file=#"C:/Users/test/task-b5cfe19-input.csv"' \
--form 'json="{\"name\": \"Test\",\"jobType\": \"BATCH_FILE\",\"runMode\": \"VALIDATE\",\"config\": {\"branchId\": \"12345\",\"trustedSource\": true}}";type=application/json'
In this case, the json form element is treated as a JSON string because of the ;type=application/json at the end.
I have tried to write the Powershell version using the new -Form parameter:
$CreateJobForm = #{
'file' = Get-Item -Path 'C:\Users\test\task-b5cfe19-input.csv'
'json' = '{"name": "Test","jobType": "BATCH_FILE","runMode": "VALIDATE","config": {"branchId": "12345","trustedSource": true}};type=application/json'
}
Invoke-RestMethod -Method Post -Uri http://localhost:8082/csv-as-input -Form $CreateJobForm
The cURL command works but the Powershell version fails because it is coming across as a text/plain type.
Is there a way to type the json field as JSON in Powershell?
You can use the -ContentType parameter to specify the content type of the request body as multipart/form-data, and then use the ConvertTo-Json cmdlet to convert the JSON object to a JSON string and include it in the form data.
$json = #{
'name' = 'Test'
'jobType' = 'BATCH_FILE'
'runMode' = 'VALIDATE'
'config' = #{
'branchId' = '12345'
'trustedSource' = $true
}
}
$CreateJobForm = #{
'file' = Get-Item -Path 'C:\Users\test\task-b5cfe19-input.csv'
'json' = (ConvertTo-Json -InputObject $json)
}
Invoke-RestMethod -Method Post -Uri http://localhost:8082/csv-as-input -ContentType 'multipart/form-data' -Form $CreateJobForm

Upload artifact using Nexus API with PowerShell

Does anybody know what the request body looks like if I want to use Nexus API to upload artifact to a repo?
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("admin123:password123"))
$header = #{authorization = "Basic $token" }
$body = #{
'raw.dictionary' = '/TestArtifact/Prod/'
'raw.asset1' = 'c:\temp\lenovo.zip'
'raw.asset1.filename' = 'lenovo.zip'
} | Convertto-Json
Invoke-RestMethod -Method POST -Uri 'http://xx.xx.xxx.xxx:8081/service/rest/v1/components?repository=TestRepo' -ContentType 'application/json'-Body $body -Headers $header
I'm getting 'Invoke-RestMethod: Response status code does not indicate success: 415 (Unsupported Media Type)'
Lets try and figure this out.
The command looks like you are trying to do is
curl -v -u admin:admin123 -X POST 'http://localhost:8081/service/rest/v1/components?repository=maven-releases' -F maven2.groupId=com.google.guava -F maven2.artifactId=guava -F maven2.version=24.0-jre -F maven2.asset1=#guava-24.0-jre.jar -F maven2.asset1.extension=jar -F maven2.asset2=#guava-24.0-jre-sources.jar -F maven2.asset2.classifier=sources -F maven2.asset2.extension=jar
It looks like the main issue we have is that you didnt convert the file to bytes.
-F #[FileName] is a Binary File
The only change really needing to be done was changing
'raw.asset1' = 'c:\temp\lenovo.zip'
to
'raw.asset1' = [System.IO.File]::ReadAllBytes("c:\temp\lenovo.zip")

How to convert curl POST with headers authorization and form to PowerShell v3.0

I have follwoing curl command which I would like to convert to PowerShell (PowerShell v3.0):
curl -s -k -H 'Authorization: api_key 1234567890' -F upload_file=#"C:\path\to\file" -X POST "https://my.url.com/submit"
What I have so far:
$Body= #{ "upload_file" = "C:\path\to\file" };
$Headers = #{ "Authorization" = "api_key 1234567890" };
$Uri = "https://my.url.com/submit"
Invoke-WebRequest -Method Post -Uri $Uri -H $Headers -Body $Body
I think the form parameter is the issue.
Thanks in advance.

Range Header Must Use Appropriate Property or Method

I've searched high and low and asked on the product forums, but cannot seem to figure this out.
Using PowerShell 5 I'm attempting to limit my results by using a range header in the way the API documentation indicates. However, I receive the following error when I try to use it.
"The 'RANGE' header must be modified using the appropriate property or
method. Parameter name: name"
I've tried:
$headers = #{
SEC= $apiKey
range="items=0-49"
}
$result = Invoke-RestMethod -Method get -Uri $global:URI -ContentType 'application/json' -Header $headers
and...
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Accept','Application/Json')
$headers.Add('RANGE','items=0-49')
$headers.Add('SEC',$ApiKey)
$result = Invoke-WebRequest -Uri $global:URI -Headers $headers -Method get
Also, here's the curl example given within the API documentation:
curl -s -X GET -u USERNAME -H 'Range: items=0-49' -H 'Version: 10.0' -H 'Accept: application/json' 'https://product.com/api/s/of'
Really appreciate any pointers on this.
Thanks in advance
It seems to be a bug in PowerShell. I found this blog page: https://sethjackson.github.io/2017/01/18/header-woes/
The workaround according to this page:
$request = [System.Net.WebRequest]::Create($uri)
$request.Method = "GET"
$request.Headers.Add("SEC", $apiKey)
# add range header
$request.AddRange("items", 0, $count)
$reader = New-Object System.IO.StreamReader($request.GetResponse().GetResponseStream())
$data = ConvertFrom-Json $reader.ReadToEnd()

Converting Curl API Call to Invoke-WebRequest in PowerShell 5

I have done a bunch of searches, but nothing so far as helped me solve this. Any help is appreciated.
I am trying to convert a curl command to Invoke-WebRequest, but for some reason I am not getting a response back. I have tried:
$headers = #{
outh_a = "WEBREQ";
oauth_key = "key";
etc...
}
Invoke-WebRequest -Uri $url -Method POST -Body "{}" -Headers $headers -Verbose
The curl command looks like this:
.\curl.exe -x POST -d "{}" -H "oauth_a: WEBREQ" -H "oauth_key:key" -H "Content-Type: application/json" -H "oauth_sm:HMAC-SHA2" -H "oauth_t:timestamp"-H "oauth_s:key+signature=" "https://example.com/services/api/request?t=data&a=data2&n=404&i=0"
The command works perfectly and returns the data. I am using PowerShell as we want to parse through the data once received. Any help is greatly appreciated.
The curl command will fail if I submit it without -d "{}", so that part is required. The server I guess is expecting to receive a specific amount of data.
I am not sure what is going on to prevent a response. I have tried curl from the same machine I am doing the PowerShell script on and it works. I even used SoapUI to make the same call and it works there too.
Edit:
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[System.Net.WebRequest]::DefaultWebProxy.Credentials =
[System.Net.CredentialCache]::DefaultCredentials
[Net.ServicePointManager]::SecurityProtocol =
[Net.SecurityProtocolType]::Ssl3, [Net.SecurityProtocolType]::Tls,
[Net.SecurityProtocolType]::Tls11, [Net.SecurityProtocolType]::Tls12
$Domain = "https://example.com/services/api/request?t=oauth_auth_token&a=appid&n=404&i=0"
# OAUTH Authorization Request Header
$Header = #{
o_nonce = 'TEST'
o_con_key = 'key'
o_sig_meth = 'type'
o_timestamp = 'timestamp'
o_sig = 'signature'
o_ver = '1.0'
o_realm = 'http://example.com/services'
}
$Body = #{}
$API_Response = Invoke-RestMethod -Method POST -Headers $Header -Uri $Domain -Body $Body -Verbose -TimeoutSec 20
Update:
#MikeW I'd have to look at your PS code in more detail, could you post the entire API call minus the sensitive information (api key etc...)?
Also, on a side note, sometimes just passing the parameters on the URI works just as well. Have you tried passing the parameters through the URI? You can see the following example of an API call I'm making using just the URI:
Invoke-RestMethod -Uri ("$EndpointURL/Tickets/$TicketID/?username=$ServiceAccount&apiKey=$APIKey");