Public/Save-OSDProgressFile.ps1
<#
.SYNOPSIS Download webfiles via Streamreader in background thread and updates progressbar in mainthread .DESCRIPTION Download webfiles via Streamreader and updates progressbar every 4% .PARAMETER URL WebURL of download file .PARAMETER File Parameter description .EXAMPLE An example .NOTES General notes #> function Save-OSDProgressFile { [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$URL, [Parameter(Mandatory)] [string]$DestinationFile ) Begin { # Check if UI is running ################################################### #Stop-NoUI } Process { try { # Tracking variable ################################################### $syncHash = [hashtable]::Synchronized(@{}) # Check destination ################################################### $fileName = $DestinationFile | Split-Path -Leaf if ((Test-UI) -or (Test-PipeServer)) { Write-Verbose "Display Progressbar for $fileName" Update-OSDProgress -DisplayBar -DownloadFile $fileName } if ($DestinationFile -match '^\.\\') { $DestinationFile = Join-Path (Get-Location -PSProvider "FileSystem") ($DestinationFile -Split '^\.')[1] } if ($DestinationFile -and !(Split-Path $DestinationFile)) { $DestinationFile = Join-Path (Get-Location -PSProvider "FileSystem") $DestinationFile } if ($DestinationFile) { $fileDirectory = $([System.IO.Path]::GetDirectoryName($DestinationFile)) if (!(Test-Path($fileDirectory))) { [System.IO.Directory]::CreateDirectory($fileDirectory) | Out-Null } } # Backround block | Download without interruption ################################################### $sb = { try { $ErrorActionPreference = 'Stop' # Create streamreader/streamwriter ################################################### $request = [System.Net.HttpWebRequest]::Create($URL) $response = $request.GetResponse() if ($response.StatusCode -eq 401 -or $response.StatusCode -eq 403 -or $response.StatusCode -eq 404) { throw "Remote file either doesn't exist, is unauthorized, or is forbidden for '$URL'." } [long]$fullSize = $response.ContentLength $fullSizeMB = $fullSize / 1024 / 1024 [byte[]]$buffer = new-object byte[] 1048576 [long]$total = [long]$count = 0 # create reader / writer $reader = $response.GetResponseStream() $writer = new-object System.IO.FileStream $DestinationFile, "Create" # Start download ################################################### $lastPercent = 0 do { $count = $reader.Read($buffer, 0, $buffer.Length) $writer.Write($buffer, 0, $count) $total += $count $totalMB = $total / 1024 / 1024 $percent = $totalMB / $fullSizeMB [int]$percentComplete = $percent * 100 # Throttle var updates ################################################### if ($fullSize -gt 0 -and ($percentComplete % 4 -eq 0) -and ($percentComplete -ne $lastPercent)) { $syncHash.cur = [int]$percentComplete $lastPercent = $percentComplete } } while ($count -gt 0) } catch { $syncHash.error = $_ } finally { # Cleanup/Dispose ################################################### if ($reader) { $reader.Close() } if ($writer) { $writer.Flush(); $writer.Close() } } } # Invoke new runspace ################################################### $rsSplatt = @{ Name = "OSDProgressFile.$filename" SetVariable = "filename", "url", "DestinationFile", "syncHash" ScriptBlock = $sb } $rs = New-psRunspace @rsSplatt # Wait for runspace | WPF/Console output in main thread ################################################### Write-Host -NoNewline -ForegroundColor DarkGray ("#" * 29) Write-Host -NoNewline -ForegroundColor Cyan " $filename " Write-Host -ForegroundColor DarkGray ("#" * 29) $lastPercent = 0 while ($lastPercent -ne 100) { if ($syncHash.error) { throw $syncHash.error } # Throttle output ################################################### [int]$curPercent = $syncHash.cur if (($curPercent -ne $lastPercent) -and ($curPercent % 4 -eq 0)) { if ((Test-UI) -or (Test-PipeServer)) { Update-OSDProgress -PercentComplete $curPercent } Write-Host -NoNewLine "`rDownload $fileName, complete : [$($curPercent.ToString("##0.00").PadLeft(6)) %]" if ($curPercent -eq 100) { Write-Host "`n" } $lastPercent = $curPercent Start-Sleep -Seconds 1 } } } catch { $ExeptionMsg = $_.Exception.Message Write-Host "Download breaks with error : $ExeptionMsg" } finally { # Cleanup if canceled via Strg+C ################################################### if ($rs.RunspaceAvailability -eq "Busy") { $rs.Closeasync() $rs.Dispose() } } } End { Update-OSDProgress -HideBar -DownloadFile " " Update-OSDProgress -PercentComplete 0 } } |