How to pass an array through a web request

Situation:

We automatically collect many reports from some web services ( PowerShell script running every night), and every day in manual mode (drag and drop in a web form) these reports are uploaded to our DB.

Now our IT department has provided us with an API that can handle this task without user interaction.

Problem:

As written in the cover letter (about this API), it waits for the reports[n] array with the file. This can be done using PHP and curl:

 $report = 'report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip'; $cfile = new CURLFile(realpath($report),'application/zip',$report); $PostData = array("reports[0]"=>$cfile); 

But how to send an array called reports[n] via PowerShell?

What I tried:

 $url = "https://test.example.com/uploadAPI/upload.php" $Source = "D:\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" $contentType = "multipart/form-data" $Username = "ApiUploadKey" $Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))} $FileContens = get-content $Source $PostData = @{"reports[0]" = $FileContens;} #$reports = @($FileContens,'application/zip',$Source) (Invoke-WebRequest -uri $url -Method POST -Headers $Headers -Body $PostData -ContentType $contentType).Content #Invoke-RestMethod -uri $url -Method POST -Headers $Headers -Body $PostData -ContentType $contentType 

This gives me the answer that I am transmitting a non-report.

EDIT 2016-10-11

Further research will lead me to this answer and this article. I tried using boundary :

 clear $url = "https://test.example.com/uploadAPI/upload.php" $filename = "report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" $Source = "D:\"+$filename $Username = "ApiUploadKey" $Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))} $FileContens = get-content $Source $enc = [System.Text.Encoding]::GetEncoding("iso-8859-1") $fileBin = [IO.File]::ReadAllBytes($Source) $fileEnc = $enc.GetString($fileBin) $boundary = [System.Guid]::NewGuid().ToString() $LF = "`n" $contentType = "multipart/form-data; boundary=--$boundary" #$bodyLines = "--"+$boundary+$LF+"Content-Disposition: form-data; name=`"reports[]`"; filename=`""+$filename+"`""+$LF+$LF+"Content-Type: application/zip"+$LF+"--"+$boundary+"--"+$LF+$LF+$FileContens+$LF+"--"+$boundary $bodyLines = ( "--$boundary", #I have tried reports[0] here too "Content-Disposition: form-data; name=`"reports[]`"; filename=`"$filename`"", # filename= is optional "Content-Type: application/zip", "", #$FileContens, $fileEnc, "--$boundary--" ) -join $LF try { #Invoke-WebRequest -Uri "https://asrp.cntd.ru/uploadAPI/" -Headers $Headers -WebSession $ws Invoke-RestMethod -Uri $url -Body $bodyLines -Method POST -Headers $Headers -ContentType $contentType -TimeoutSec 50 } catch [System.Net.WebException] { Write-Error( "FAILED to reach '$url': $_" ) throw $_ } 

But with the same results.

Also I tried this:

 $wc = new-object System.Net.WebClient $wc.Credentials = new-object System.Net.NetworkCredential("ApiUploadKey","") ls "D:\*.zip" | foreach { $wc.UploadFile('https://test.example.com/uploadAPI/upload.php', $_.FullName ) write-host $_.FullName } 

And one more solution from this answer :

 Invoke-RestMethod -Uri $url -InFile $Source -ContentType "multipart/form-data" -Method POST -Headers $Headers 

Always the same answer - not a report

EDIT 2016-10-17

curl

I downloaded curl for windows. And use it like:

 curl.exe https://test.example.com/uploadAPI/upload.php --user ApiUploadKey: --form "reports[0] =@d :\report_746_226255_20161010_1635.zip;type=application/zip" 

And it gave me:

 [{"code" : 102 , "guid" : "{23CE9F7F-BEC8-4D4C-8AC3-2865CFA94FBD}" , "id" : "5804902bc73a2475177464", "filename" : "report_746_226255_20161010_1635.zip"}] 

So, with curl, it works great!

insole

I donโ€™t know exactly what to do with the magazine.

When I submit the file as follows:

 POST https://test.example.com/uploadAPI/upload.php Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468 User-Agent: Fiddler Host: test.example.com Authorization: Basic ... Content-Length: 21075175 

Request body:

 ---------------------------acebdf13572468 Content-Disposition: form-data; name="reports[]"; filename="report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip" Content-Type: application/zip <@INCLUDE *D:\report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip*@> ---------------------------acebdf13572468-- 

I got

 HTTP/1.1 200 OK Date: Mon, 17 Oct 2016 10:04:43 GMT Server: Apache/2.4.20 (Win64) OpenSSL/1.0.2h PHP/7.0.6 X-Powered-By: PHP/7.0.6 Set-Cookie: SESSION_UPLOAD_ID=.....; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Connection: close Content-Length: 193 Content-Encoding: none Accept-Ranges: bytes Content-Type: text/html; charset=UTF-8 [{"code" : 102 , "guid" : "{B67A9D89-368B-4665-96AC-77C2CA0F4766}" , "id" : "5804a23be4152532018928", "filename" : "report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip"}] 
+1
powershell webrequest
source share
1 answer

The PHP code uses the Curl class and sets $ PostData as:

  $PostData = array("reports[0]"=>$cfile); 

$ PostData is an array of key / value pairs (in PHP), and the key is called Reports [0] . it's just the string name is the key, not the element of the array.

in the curl commandLine tool we can load the file using the command:

  curl.exe -F Reports[0] =@ "I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" http://MyServer/uploader/api/upload 

or maybe (pay attention to the key Reports [0] [2] [3]):

  curl.exe -F Reports[0][2][3] =@ "I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" http://asd-pc/uploader/api/upload 

-F - to enter a key / value pair of the form Note @ before the file name Try it on your server and view the session in Fiddler to find out how curl and PHP send the request to the server.

You can pass other parameters, such as -H (header) -v (verbose) -F to other files with a different key name, for example Reports 1 .

I tested this code using my web server, which runs the Web Api2 service, which uploads the file to the server and works fine.

So, the problem is this: how to convert this code to work with Powershell.

In curl, either PHP or a command line tool, it automatically prepares the request header and body for loading files that support Multipart / form-data.

Both Powershell commands: Invoke-WebRequest and Invoke-RestMethod do not know how to format the request body to conform to the Multipart / form-data standard, as specified in the RFC Forms: multipart / form-data

You must manually set the body of the message and then call your call

Next script Uploading a file to a web server using powershell.

I installed Content-Type: application / octet-stream to support any type, including zip files.

  function Upload-File ( $InFile,$Uri ) { $Username = "ApiUploadKey" $Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))} $LF = "`n" $fileName = Split-Path $InFile -leaf $boundary = [System.Datetime]::Now.Ticks.ToString() $binaryData = [System.IO.File]::ReadAllBytes($InFile) $binaryEncoded=[System.Text.Encoding]::GetEncoding("iso-8859-1").GetString($binaryData) $ContentType = "application/octet-stream" $body = @" --$boundary Content-Disposition: form-data; name=`"Reports[0]`"; filename=`"$fileName`" Content-Type: $ContentType $LF $binaryEncoded --$boundary-- $LF "@ try { return Invoke-RestMethod -Uri $Uri -Method Post -ContentType "multipart/form-data; boundary=$boundary" -Body $body -Headers $Headers } catch [Exception] { $PSCmdlet.ThrowTerminatingError($_) } } #-- test the function --------------------------------- cls $uri = "http://MyServer/uploader/api/upload" $filePath = "I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" $response = Upload-File -InFile $filePath -Uri $uri #-Credential $credentials $response 

Output Session from fiddler

  POST http://MyServer/uploader/api/upload HTTP/1.1 Authorization: Basic QXBpVXBsb2FkS2V5Og== User-Agent: Mozilla/5.0 (Windows NT; Windows NT 6.1; en-US) WindowsPowerShell/5.0.10586.117 Content-Type: multipart/form-data; boundary=636123339963709320 Host: MyServer Content-Length: 379 Connection: Keep-Alive --636123339963709320 Content-Disposition: form-data; name="Reports[0]"; filename="report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" Content-Type: application/octet-stream xxxxxxxxxxxxxxxxxxxxxxxxxxxStream of byte sxxxxxxxxxxxxxxx 

In the above session data, you see Reports [0] called name

You can use the same code with the command: Invoke-WebRequest

+1
source share

All Articles