Downloading files from the internet in PowerShell (with progress)
Ok, so the easiest way (that I know of) to download files in powershell from the internet is to use the .net WebClient. The simple way I started with was the two liner:
$client = New-Object "System.Net.WebClient"
$client.DownloadFile("https://somesite.com/largefile.zip","c:\temp\largefile.zip"
However I was working on a script that required some pretty large files to be downloaded, and using the DownloadFile method has no progress indicator. I figured some users might thing the program died. So I decided to create a method that still uses the webclient to download the files, however give a status of where it is in the download. Here is what I came up with, hopefully someone else will find it useful.
function downloadFile($url, $targetFile)
{
"Downloading $url"
$uri = New-Object "System.Uri" "$url"
$request = [System.Net.HttpWebRequest]::Create($uri)
$request.set_Timeout(15000) #15 second timeout
$response = $request.GetResponse()
$totalLength = [System.Math]::Floor($response.get_ContentLength()/1024)
$responseStream = $response.GetResponseStream()
$targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $targetFile, Create
$buffer = new-object byte[] 10KB
$count = $responseStream.Read($buffer,0,$buffer.length)
$downloadedBytes = $count
while ($count -gt 0)
{
[System.Console]::CursorLeft = 0
[System.Console]::Write("Downloaded {0}K of {1}K", [System.Math]::Floor($downloadedBytes/1024), $totalLength)
$targetStream.Write($buffer, 0, $count)
$count = $responseStream.Read($buffer,0,$buffer.length)
$downloadedBytes = $downloadedBytes + $count
}
"`nFinished Download"
$targetStream.Flush()
$targetStream.Close()
$targetStream.Dispose()
$responseStream.Dispose()
}
This would be used like
downloadFile "https://somesite/largefile.zip" "c:\temp\largefile.zip"
Comments
Anonymous
December 20, 2012
Hey, thanks! Good function. I've modified the code a bit, so that it would support the 'Write-Progress' cmdlet: function DownloadFile($url, $targetFile) { $uri = New-Object "System.Uri" "$url" $request = [System.Net.HttpWebRequest]::Create($uri) $request.set_Timeout(15000) #15 second timeout $response = $request.GetResponse() $totalLength = [System.Math]::Floor($response.get_ContentLength()/1024) $responseStream = $response.GetResponseStream() $targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $targetFile, Create $buffer = new-object byte[] 10KB $count = $responseStream.Read($buffer,0,$buffer.length) $downloadedBytes = $count while ($count -gt 0) { $targetStream.Write($buffer, 0, $count) $count = $responseStream.Read($buffer,0,$buffer.length) $downloadedBytes = $downloadedBytes + $count Write-Progress -activity "Downloading file '$($url.split('/') | Select -Last 1)'" -status "Downloaded ($([System.Math]::Floor($downloadedBytes/1024))K of $($totalLength)K): " -PercentComplete ((([System.Math]::Floor($downloadedBytes/1024)) / $totalLength) * 100) } Write-Progress -activity "Finished downloading file '$($url.split('/') | Select -Last 1)'" $targetStream.Flush() $targetStream.Close() $targetStream.Dispose() $responseStream.Dispose() }Anonymous
June 10, 2013
Awesome with the Write-Progress addition! Thx lime!Anonymous
September 22, 2013
Nice bit of code that, thanks guys!Anonymous
September 08, 2014
Problem with the code when the download file is less than 1024 bytes. I corrected by doing an If/else statement that checks for file length less than 1024: $responseContentLength = $response.get_ContentLength() if(-not ($responseContentLength -lt 1024)) { $totalLength = [System.Math]::Floor($response.get_ContentLength()/1024) } else { $totalLength = [System.Math]::Floor(1024/1024) }Anonymous
August 04, 2015
I'm getting an exception error You cannot call a method on a null-valued expression. At line:18 char:9
- $targetStream.Write($buffer, 0, $count)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull Exception setting "CursorLeft": "The handle is invalid. " At line:16 char:9
- [System.Console]::CursorLeft = 0
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], SetValueInvocationException + FullyQualifiedErrorId : ExceptionWhenSetting