I try to upload a file to a uri with POST. I somehow fail. I got help from
powershell invoke-restmethod multipart/form-data
but they uploaded a text file.
Also the curl command works:
curl -X POST "https://some.place.over.the.rainbow.com/api/v1/dataupdate" -H "accept: */*" -H "Authorization: Basic 123123123123" -F "file=#/c/updates/SomeFile.zip"
In my ps1 Script I tried following:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$Headers = #{
Authorization = "Basic 123123123123"
};
$FilePath = "C:\Users\asd\SomeFile.zip";
$Uri = 'ttps://some.place.over.the.rainbow.com/api/v1/dataupdate';
$LF = "`r`n";
$boundary = [System.Guid]::NewGuid().ToString();
$fileBytes = [System.IO.File]::ReadAllBytes($FilePath);
$fileEnc = [System.Text.Encoding]::GetEncoding('UTF-8').GetString($fileBytes);
$bodyLines = (
"--$boundary",
"Content-Disposition: form-data; name=`"file`"; filename=`"SomeFile.zip`"",
$fileEnc,
"--$boundary--$LF"
) -join $LF
Invoke-RestMethod -Uri $Uri -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -Headers $Headers -Body $bodyLines
On Serverside I get
Servlet.service() for servlet [dispatcherServlet] in context with path [/...] threw exception [Request processing failed; nested exception is
org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request;
nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException:
Header section has more than 10240 bytes (maybe it is not properly terminated)] with root cause
org.apache.tomcat.util.http.fileupload.MultipartStream$MalformedStreamException: Header section has more than 10240 bytes (maybe it is not properly terminated)at
org.apache.tomcat.util.http.fileupload.MultipartStream.readHeaders(MultipartStream.java:523)
~[tomcat-embed-core-8.5.34.jar!/:8.5.34]at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:880)
~[tomcat-embed-core-8.5.34.jar!/:8.5.34]at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:845)
I need to execute it on a windows machine where I do not haver curl unfortunately.
Appreciate any help
Related
I am trying to use the Invoke-RestMethod to upload an attachment to a Smartsheet using the API.
This is the curl example from the Smartsheet API Documentation:
curl https://api.smartsheet.com/2.0/sheets/{sheetId}/attachments \
-H "Authorization: Bearer ll352u9jujauoqz4gstvsae05" \
-H "Content-Type: application/msword" \
-H 'Content-Disposition: attachment; filename="ProgressReport.docx"' \
-H "Content-Length: FILE_SIZE" \
-X POST \
--data-binary #ProgressReport.docx
This is my Powershell code.
$BaseURI = "https://api.smartsheet.com/2.0"
$Id = {sheet id} #sheet id passed a parameter
$Uri = "{0}/sheets/{1}/attachments" -f $BaseUri, $id
$mimetype = ""application/vnd.openxmlformats-officedocument.wordprocessingml.document"
$FileName = "MyDocument.docx"
$Config = Read-Config #reads authentication token from text file"
$token = ConvertTo-SecureString -String $config.APIKey -AsPlainText -Force
$response = Invoke-RestMethod -Method POST -Uri $Uri -InFile $FileName -ContentType $mimetype -Authentication:Bearer -token $token
What I get is this response:
{ "errorCode" : 1008, "message" : "Unable to parse request. The following error occurred: Request body must be either a JSON
| object or JSON array.", "refId" : "12y60zzovzndm" }
If I try to post a text file with just the work "test" in it I get this error.
{ "errorCode" : 1008, "message" : "Unable to parse request. The following error occurred: Unrecognized token 'test': was expecting 'null', 'true', 'false' or NaN\n at [Source: REST input; line: 1, column: 6]", "refId" : "lbstw0mq73l9" }
If I do this API call in Postman it works fine.
I know there is a C# SDK but I'm building a PowerShell module and I don't want those .dll files as a requirement for this module.
OK I got this to work thanks to Postman.
I build the headers as a hashtable"
Name Value
---- -----
Content-Type application/vnd.openxmlformats-officedocument.wordprocessingml.document
Authorization Bearer VcjJ....
Content-Disposition attachment; filename="CWilliams.docx"
Convert the input file into a byte array with:
$body = [System.IO.File]::ReadAllBytes($path)
Then issue the statement:
$response = Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $Headers -Body $body
From what I understand about the Invoke-RestMethod function the -inFile parameter is supposed to handle all this for you but it doesn't work with the Smartsheet API.
I would like to upload a file to my GLPI from API.
This curl command works fine :
curl -X POST
-H 'Content-Type: multipart/form-data'
-H 'Session-Token: $sessiontoken'
-H 'App-Token:$apptoken'
-F 'uploadManifest={"input": {"name": "Uploaded document", "_filename" : ["file.txt"]}};type=application/json'
-F 'filename[0]=#file.txt' 'http://GLPI_SERVER/glpi/apirest.php/Document'
The same curl in powershell (Thank's to Jean-Christophe from GLPI) :
$DocumentUpload = C:\curl\bin\curl.exe `
-X POST `
-H 'Content-Type: multipart/form-data' `
-H "Session-Token: $($SessionToken.session_token)" `
-H 'App-Token: '$AppToken `
-F 'uploadManifest={\"input\": {\"name\": \"Document ticket 161\", \"_filename\" : [\"clear.png\"], \"tickets_id\":\"161\"}};type=application/json' `
-F 'filename[0]=#"C:\temp1\clear.png"' `
-s `
-k 'https://glpi.xxxx.fr/apirest.php/Document/'
I would like use the Invoke-RestMethod but without success
# GLPI REST API CONFIG :
$AppURL = "https://glpi.xxxxxxxxxxxx.fr/apirest.php"
$UserToken = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
$AppToken = "XXXXXXXXXXX"
$ID = 161
$ItemType = "Ticket"
$SubItemType = "Document"
$manifest = #{}
$SessionToken = Invoke-RestMethod "$AppURL/initSession" -Method Get -Headers #{"Content-Type" = "application/json";"Authorization" = "user_token $UserToken";"App-Token"=$AppToken}
$FileContent = [System.IO.File]::ReadAllBytes("C:\temp1\clear.png")
$input = New-Object System.Collections.ArrayList
$type =New-Object System.Collections.ArrayList
$filename =New-Object System.Collections.ArrayList
$input = #{input=#{"name"="titre";"_filename"="clear.png";"tickets_id"="161"}}
$type = #{"type"="application/json"}
$filename =#{"filename[0]"="C:\temp1\clear.png"}
$manifest.Add("uploadManifest",$input)
$manifest.Add("type=","application/json")
$manifest.Add("filename[0]=",#("C:\temp1\clear.png"))
$json = #($manifest | ConvertTo-Json)
#Display Convert to JSON
#$json
Invoke-RestMethod "$AppURL/$($ItemType)/$($ID)/$($SubItemType)" -Method Post -Headers #{"session-token"=$SessionToken.session_token; "App-Token" = $AppToken} -Body ([System.Text.Encoding]::UTF8.GetBytes($json)) -ContentType 'multipart/data'
## Test autre ContentType
Invoke-RestMethod "$AppURL/$($ItemType)/$($ID)/$($SubItemType)" -Method Post -Headers #{"session-token"=$SessionToken.session_token; "App-Token" = $AppToken} -Body ([System.Text.Encoding]::UTF8.GetBytes($json)) -ContentType 'multipart/form-data'
#Kill session
Invoke-RestMethod "$AppURL/killSession" -Headers #{"session-token"=$SessionToken.session_token; "App-Token" = "$AppToken"}
The Invoke with : -ContentType 'multipart/data'
["ERROR_BAD_ARRAY","The input parameter must be an array of objects
The Invoke with : -ContentType 'multipart/form-data'
["ERROR_UPLOAD_FILE_TOO_BIG_POST_MAX_SIZE","The file seems too big"]
I thank in advance if someone sees my mistakes and help me.
Same topic to : How convert curl file upload command to Invoke-RestMethod?
press f12 in chrome to open devtools, go to network tab (probably good idea to enable XHR filter too)
manually upload file - new requests will show up in devtools
find the one that uploads file
right click - copy - as powershell
that will copy entire request that you can then adjust/review to have better idea of what goes where
Thank's for your answer Charg, but when i try there are lot of change and pages. I have try this option before post here :D. Because for me the copy is not useable. Maybe easiest for you :
I have to create a new reply because the comment does not allow enough characters.
(i have deleted headers)
Invoke-WebRequest -Uri "https://glpi.XXXXXXXXXXXX.fr/ajax/fileupload.php" `
-Method "POST" `
-Headers #{
} `
-ContentType "multipart/form-data; boundary=----WebKitFormBoundarysgETZNBiXoMdeht2Q" `
-Body ([System.Text.Encoding]::UTF8.GetBytes("------WebKitFormBoundarysgETZNBiXoMdeht2Q$([char]13)$([char]10)Content-Disposition: form-data; name=`"name`"$([char]13)$([char]10)$([char]13)$([char]10)filename$([char]13)$([char]10)------WebKitFormBoundarysgETZNBiXoMeht2Q$([char]13)$([char]10)Content-Disposition: form-data; name=`"showfilesize`"$([char]13)$([char]10)$([char]13)$([char]10)1$([char]13)$([char]10)------WebKitFormBoundarysgETZNBiXoMeht2Q$([char]13)$([char]10)Content-Disposition: form-data; name=`"filename[]`"; filename=`"apple.png`"$([char]13)$([char]10)Content-Type: image/png$([char]13)$([char]10)$([char]13)$([char]10)$([char]13)$([char]10)------WebKitFormBoundarysgETZNBiXoMeht2Q--$([char]13)$([char]10)"))
And other body (more informations) :
-Body ([System.Text.Encoding]::UTF8.GetBytes("------WebKitFormBoundarymPxXKSWBW70lLtX2 $([char]13)$([char]10)Content-Disposition: form-data; name=`"documentcategories_id`"$([char]13)$([char]10)$([char]13)$([char]10)10$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"entities_id`"$([char]13)$([char]10)$([char]13)$([char]10)2$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"is_recursive`"$([char]13)$([char]10)$([char]13)$([char]10)0$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"itemtype`"$([char]13)$([char]10)$([char]13)$([char]10)Ticket$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"items_id`"$([char]13)$([char]10)$([char]13)$([char]10)161$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"tickets_id`"$([char]13)$([char]10)$([char]13)$([char]10)161$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"_filename[0]`"$([char]13)$([char]10)$([char]13)$([char]10)6075d0cb639f08.69946676apple.png$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"_prefix_filename[0]`"$([char]13)$([char]10)$([char]13)$([char]10)6075d0cb639f08.69946676$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"_tag_filename[0]`"$([char]13)$([char]10)$([char]13)$([char]10)ea6f951c-f37490bd-6075d0cb7fc703.58112843$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"filename[]`"; filename=`"`"$([char]13)$([char]10)Content-Type: application/octet-stream$([char]13)$([char]10)$([char]13)$([char]10)$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"add`"$([char]13)$([char]10)$([char]13)$([char]10)Ajouter un nouveau fichier$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2$([char]13)$([char]10)Content-Disposition: form-data; name=`"_glpi_csrf_token`"$([char]13)$([char]10)$([char]13)$([char]10)583040be8c019c6b482ff61d4c6c37230109cb37876001d086603c1b4a144eb0$([char]13)$([char]10)------WebKitFormBoundarymPxXKSWBW70lLtX2--$([char]13)$([char]10)"))
And I found a guy, who wrote this part in Python (maybe help to translate to powershell ?)
multipart_form_data = {
'uploadManifest': (None, '{"input": {"name": "test123.png", "_filename": ["test123.png"]}}'),
'file': ('test123.png', open('test123.png', 'rb')),
}
And one other guy find his solution in C# (i have losted the post id)
// Upload
var RSClient = new RestClient(Properties.Settings.Default.GLPI_URL);
var request = new RestRequest("Document", Method.POST);
request.AddHeader("Session-Token", Properties.Settings.Default.GLPI_SESSION_TOKEN);
request.AddHeader("App-Token", Properties.Settings.Default.GLPI_APP_TOKEN);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "multipart/form-data");
request.AddQueryParameter("uploadManifest", "{\"input\": {\"name\": \"UploadFileTest\", \"_filename\": \"GiletsJaunes.jpg\"}}");
request.AddFile("test", #"C:\path\to\File.jpg");
IRestResponse response = RSClient.Execute(request);
var content = response.Content;
textBox2.Text = textBox2.Text + Environment.NewLine + content;
This curl command works:
curl -v -X POST https://subdomain.playvox.com/api/v1/files/upload?context=quality -H "Content-Type: multipart/form-data" -u [username]:[password] -F file=#c:\path\to\file.wav
But I am unable to perform the same thing in PowerShell using the Invoke-RestMethod cmdlet. Here's my attempt:
$file_contents = [System.IO.File]::ReadAllBytes($($file_path))
Invoke-RestMethod -Uri "https://subdomains.playvox.com/api/v1/files/upload?context=quality" -Method Post -ContentType "multipart/form-data" -Headers #{ "Authorization" = "Basic $($playvox_base64_auth)" } -Body #{ file = $file_contents }
When run the API responds with invalid_param, "file" is required. However I confirmed the call to ReadAllBytes succeeds and gives back the raw file data. It seems like PowerShell is not sending the request body in the right format? I've looked at several other answers here and documentation online and nothing I found has worked.
Discovered there is a -Form parameter in Powershell 6 and later. I updated my powershell and used the following instead:
$file_contents = Get-Item $file_path
Invoke-RestMethod -Uri "https://subdomains.playvox.com/api/v1/files/upload?context=quality" -Method Post -ContentType "multipart/form-data" -Headers #{ "Authorization" = "Basic $($playvox_base64_auth)" } -Form #{ file = $file_contents }
And it worked.
I'm trying to upload a text file in our Salesforce application using PowerShell.
The curl code which I'm trying to mimic in PowerShell is:
curl -X POST -H "Authorization: {SESSION_ID}" \
-H "Content-Type: multipart/form-data" \
-F file=#document.txt \
-F "name__v=myDocument" \
-F "type__v=Undefined" \
-F "lifecycle__v=Unclassified" \
https://{server}/api/{version}/objects/documents
Here is the PowerShell code which I have written taking hint from the web:
$URL="https://{server}/api/{version}/auth"
$CT="application/x-www-form-urlencoded"
$User="user"
$Password="pass"
$SessionID=(Invoke-RestMethod -Method Post -Uri $URL -Body #{"Content-Type" = $CT; "username" = $User; "password" = $Password}).sessionId
$URL="https://{server}/api/{version}/objects/documents"
$boundary=[System.Guid]::NewGuid().ToString()
$LF="`r`n"
$File=Get-Content("....\test.txt")
$fileBin=[System.IO.File]::ReadAllBytes("....\test.txt")
$enc=[System.Text.Encoding]::GetEncoding("iso-8859-1")
$fileEnc=$enc.GetString($fileBin)
$Body1=(
"--$boundary",
"Content-Disposition: form-data; name__v=`"kaz.txt`"; type__v=`"Undefined`"; lifecycle__v=`"Unclassified`"",
"Content-Type: application/octet-stream$LF",
$fileEnc,
"--$boundary--$LF"
) -join $LF
$Body2 = (
"file=$File; name__v=`"kaz.txt`"; type__v=`"Undefined`"; lifecycle__v=`"Unclassified`""
)
Invoke-RestMethod -Method POST -Uri $URL -Headers #{"Authorization" = $SessionID; "Content-Type" = "multipart/form-data; boundary=`"$boundary`""} -Body $Body1
Invoke-RestMethod -Method POST -Uri $URL -Headers #{"Authorization" = $SessionID; "Content-Type" = "multipart/form-data; boundary=`"$boundary`""} -Body $Body2
None of these are working and I'm getting error
PARAMETER_REQUIRED lifecycle__v: Missing required parameter : lifecycle__v.
I modified the body and now its working fine
$Body = (
"--$boundary", "Content-Disposition: form-data; name=`"file`"; filename=`"test.docx`"", "Content-Type: application/octet-stream$LF", $fileEnc,
"--$boundary", "Content-Disposition: form-data; name=`"lifecycle__v`"", "", "Unclassified",
"--$boundary", "Content-Disposition: form-data; name=`"type__v`"", "", "Undefined",
"--$boundary--"
)-join $LF
Invoke-RestMethod -Method POST -Uri $URL -Headers #{"Authorization" = $SessionID; "Content-Type" = "multipart/form-data; boundary=$boundary"} -Body $Body
I'm trying to use the Invoke-RestMethod cmdlet in PowerShell 3 and 4, to upload a large binary file using a REST API's multipart/form-data upload. Here is a working cURL example on how to perform what I want to do in PowerShell:
curl -i -k -H "accept: application/json" -H "content-type: multipart/form-data" -H "accept-language: en-us" -H "auth: tokenid" -F file="#Z:\large_binary_file.bin" -X POST "https://server/rest/uri2"
I would love to see a working example on how to use Invoke-RestMethod to POST a multipart/form-data. I found a blog post from the PowerShell team showing how to use Invoke-RestMethod to upload to OneDrive (aka SkyDrive), but doesn't work well. I'd also like to avoid using System.Net.WebClient if at all possible. I also found another thread here on Stackoverflow, but it really didn't help much.
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
$server = "https://server"
uri = "/rest/uri1"
$headers = #{"accept" = "application/json"; "content-type" = "application/json";"accept-language" = "en-us"}
$body = #{"userName" = "administrator"; "password" = "password"}
$method = "POST"
#Get Session ID
$resp = Invoke-RestMethod -Method $method -Headers $headers -Uri ($server+$uri) -body (convertto-json $Body -depth 99)
$sessionID = $resp.sessionID
#Upload file
$uri = "/rest/uri2"
$headers = #{"accept" = "application/json";"content-type" = "multipart/form-data"; "accept- language" = "en-us"; "auth" = $sessionID}
$medthod = "POST"
$largeFile = "Z:\large_binary_file.bin"
I have tried both ways of using Invoke-RestMethod:
Invoke-RestMethod -Method $method -Headers $headers -Uri ($server+$uri) -InFile $largeFile
or
$body = "file=$(get-content $updateFile -Enc Byte -raw)"
Invoke-RestMethod -Method $method -Headers $headers -Uri ($server+$uri) -body $body
I notice couple of mistakes in your invoke statement. First, you need to use POST keyword instead of string value. Second, make sure that Content-Type is set to multipart/form-data. So this is my revised statement -
$uri = "http://blahblah.com"
$imagePath = "c:/justarandompic.jpg"
$upload= Invoke-RestMethod -Uri $uri -Method Post -InFile $imagePath -ContentType 'multipart/form-data'
You can check the response from the server by checking $upload.