Menu

Powershell Download Function with Progress

This file download function is a modified version of the one found in the top comment here. I wanted to format the file sizes a little better and make the function slightly more robust.

I found a file size conversion function that seemed to work well for me. The function is available for download from the TechNet Gallery. You can read more about the function on Boe’s blog post here.

I added an ExtraVerbose switch to suppress the verbose output from the size conversion function unless it is desired.

Function Download-File {
    [cmdletbinding()]
    Param (
        [parameter(Mandatory=$True,Position=0)][Alias("Source","URL")][string]$dlURL,
		[parameter(Mandatory=$False,Position=1)][Alias("Target","File")][string]$dlFile = "$((Get-Item -Path ".\" -Verbose).FullName)\$(($dlURL.split('/') | Select -Last 1).Split('?') | Select -First 1)",
        [parameter(Mandatory=$False)][switch]$ExtraVerbose = $False
    )
    if($ExtraVerbose) {
        $oldverbose = $VerbosePreference
        $VerbosePreference = "continue" 
    }
    $dlRequired = $true
    Write-Verbose ("Connecting to website")
	$webRequest = [System.Net.HttpWebRequest]::Create($dlURL)
	$webRequest.set_Timeout(15000) #15 second timeout
	$webResponse = $webRequest.GetResponse()
    $webLength = [System.Math]::Floor($webResponse.get_ContentLength())
    if(Test-Path $dlFile) {
        Write-Verbose ("File exists checking modified date and file size")
        $localMod = (Get-Item $dlFile).LastWriteTime
		$localLength = (Get-Item $dlFile).Length
        $webMod = ($webResponse.LastModified) -as [DateTime]
        if (($webMod -le $localMod) -and ($webLength -eq $localLength)) {
            Write-Verbose ("File is the same size and date is same or newer, no download necessary")
            $dlRequired = $false
        }
    }
    if ($dlRequired) {
		$responseStream = $webResponse.GetResponseStream()
        Write-Verbose ("Creating file stream")
		$targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $dlFile,Create
		$buffer = New-Object byte[] 10KB
		$count = $responseStream.Read($buffer,0,$buffer.length)
		$downloadedBytes = $count
        Write-Verbose ("Downloading file")
		while ($count -gt 0) {
			$targetStream.Write($buffer, 0, $count)
			$count = $responseStream.Read($buffer,0,$buffer.length)
			$downloadedBytes = $downloadedBytes + $count
			Write-Progress -Activity "Downloading file '$(($dlURL.split('/') | Select -Last 1).Split('?') | Select -First 1)'" -Status "Downloaded $(Convert-Size -Size $downloadedBytes -Verbose:$ExtraVerbose) of $(Convert-Size -Size $webLength -Verbose:$ExtraVerbose))" -PercentComplete (($downloadedBytes / $webLength) * 100)
		}
		Write-Progress -Activity "Downloading file '$(($dlURL.split('/') | Select -Last 1).Split('?') | Select -First 1)'" -Status "Download complete." -Completed
        Write-Verbose ("File download complete")
		$targetStream.Flush()
		$targetStream.Close() 
		$targetStream.Dispose() 
		$responseStream.Dispose() 
    }
    $webResponse.Close()
	$webResponse.Dispose()
    $VerbosePreference = $oldverbose
}

Leave a Reply

Your email address will not be published. Required fields are marked *