I'm trying to upload really big VM Images (5-15 Gb size) to an HTTP server using PowerShell.
I tried to use for that few methods (here links to script with net.WebClient.UploadFile and script with Invoke-webRequest)
It works well for files less than 2GB, but not for files larger than this.
I'm trying to work with httpWebRequest directly but I unable to put FileStream
into it.
So my question is: how to put filestream into webrequest?
Or more generally: how to upload huge file via http with PowerShell?
$Timeout=10000000;
$fileName = "0.iso";
$data = "C:\\$fileName";
$url = "http://nexus.lab.local:8081/nexus/content/sites/myproj/$fileName";
#$buffer = [System.IO.File]::Open("$data",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read) #Err Cannot convert argument "buffer", with value: "System.IO.FileStream", for "Write" to type "System.Byte[]":
#$buffer = gc -en byte $data # too much space in memory
$buffer = [System.IO.File]::ReadAllBytes($data) #Limit 2gb
[System.Net.HttpWebRequest] $webRequest = [System.Net.WebRequest]::Create($url)
$webRequest.Timeout = $timeout
$webRequest.Method = "POST"
$webRequest.ContentType = "application/data"
#$webRequest.ContentLength = $buffer.Length;
$webRequest.Credentials = New-Object System.Net.NetworkCredential("admin", "admin123");
$requestStream = $webRequest.GetRequestStream()
$requestStream.Write($buffer, 0, $buffer.Length)
$requestStream.Flush()
$requestStream.Close()
[System.Net.HttpWebResponse] $webResponse = $webRequest.GetResponse()
$streamReader = New-Object System.IO.StreamReader($webResponse.GetResponseStream())
$result = $streamReader.ReadToEnd()
return $result
$stream.Close()
We have three ways to shorten the time sending extensive data by HTTP: compress data. send chunked data. request data in a selected range.
A multipart request is a HTTP request that HTTP clients construct to send files and data over to a HTTP Server. It is commonly used by browsers and HTTP clients to upload files to the server.
MyAirBridge. With MyAirBridge(Opens in a new window), you can upload a file and email a link to a specific recipient or just upload the file and generate a link to share with anyone. You can send a file as large as 20GB for free.
Configure 'HTTP Request' actionMethod (Mandatory): Select the HTTP method that you wish to use. Since we wish to upload the file, select POST method. URL (Mandatory): Enter the URL of the service to which you wish to upload the file. For this example, we will enter the URL for Built.io Backend.
By default HttpWebRequest is buffering data in memory.
Just set HttpWebRequest.AllowWriteStreamBuffering
property to false and you would be able to upload files with almost any size.
See more details at msdn
Thank you @Stoune, it was last thing that helped to receive finally working solution.
One more, it is need to organize stream file reading and writing to the webrequest buffer. And it possibly to do with that piece of code:
$requestStream = $webRequest.GetRequestStream()
$fileStream = [System.IO.File]::OpenRead($file)
$chunk = New-Object byte[] $bufSize
while( $bytesRead = $fileStream.Read($chunk,0,$bufsize) )
{
$requestStream.write($chunk, 0, $bytesRead)
$requestStream.Flush()
}
And final script look like this:
$user = "admin"
$pass = "admin123"
$dir = "C:\Virtual Hard Disks"
$fileName = "win2012r2std.vhdx"
$file = "$dir/$fileName"
$url = "http://nexus.lab.local:8081/nexus/content/sites/myproj/$fileName"
$Timeout=10000000
$bufSize=10000
$cred = New-Object System.Net.NetworkCredential($user, $pass)
$webRequest = [System.Net.HttpWebRequest]::Create($url)
$webRequest.Timeout = $timeout
$webRequest.Method = "POST"
$webRequest.ContentType = "application/data"
$webRequest.AllowWriteStreamBuffering=$false
$webRequest.SendChunked=$true # needed by previous line
$webRequest.Credentials = $cred
$requestStream = $webRequest.GetRequestStream()
$fileStream = [System.IO.File]::OpenRead($file)
$chunk = New-Object byte[] $bufSize
while( $bytesRead = $fileStream.Read($chunk,0,$bufsize) )
{
$requestStream.write($chunk, 0, $bytesRead)
$requestStream.Flush()
}
$responceStream = $webRequest.getresponse()
#$status = $webRequest.statuscode
$FileStream.Close()
$requestStream.Close()
$responceStream.Close()
$responceStream
$responceStream.GetResponseHeader("Content-Length")
$responceStream.StatusCode
#$status
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With