Skip to content

Commit a6334b4

Browse files
Restore Save-Webfile.ps1 to upstream/master version
1 parent 9d64fcb commit a6334b4

File tree

1 file changed

+54
-15
lines changed

1 file changed

+54
-15
lines changed

Public/Functions/Other/Save-WebFile.ps1

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ function Save-WebFile {
1111
[OutputType([System.IO.FileInfo])]
1212
param
1313
(
14-
[Parameter(Position=0, Mandatory, ValueFromPipelineByPropertyName)]
14+
[Parameter(Position = 0, Mandatory, ValueFromPipelineByPropertyName)]
1515
[Alias('FileUri')]
1616
[System.String]
1717
$SourceUrl,
@@ -44,8 +44,7 @@ function Save-WebFile {
4444
#=================================================
4545
# DestinationDirectory
4646
#=================================================
47-
if (Test-Path "$DestinationDirectory")
48-
{
47+
if (Test-Path "$DestinationDirectory") {
4948
Write-Verbose "Directory already exists at $DestinationDirectory"
5049
}
5150
else {
@@ -62,8 +61,8 @@ function Save-WebFile {
6261
Remove-Item -Path $DestinationNewItem.FullName -Force | Out-Null
6362
}
6463
else {
65-
Write-Warning "Unable to write to Destination Directory"
66-
Break
64+
Write-Warning 'Unable to write to Destination Directory'
65+
break
6766
}
6867
#=================================================
6968
# DestinationName
@@ -83,8 +82,8 @@ function Save-WebFile {
8382
#=================================================
8483
# OverWrite
8584
#=================================================
86-
if ((-NOT ($PSBoundParameters['Overwrite'])) -and (Test-Path $DestinationFullName)) {
87-
Write-Verbose "DestinationFullName already exists"
85+
if ((-not ($PSBoundParameters['Overwrite'])) -and (Test-Path $DestinationFullName)) {
86+
Write-Verbose 'DestinationFullName already exists'
8887
Get-Item $DestinationFullName -Force
8988
}
9089
else {
@@ -116,17 +115,57 @@ function Save-WebFile {
116115
else {
117116
Write-Verbose "cURL Source: $SourceUrl"
118117
Write-Verbose "Destination: $DestinationFullName"
119-
$Headers = Invoke-Expression "& curl.exe --head --silent --insecure --location --url `"$SourceUrl`""
120-
if ($Headers[0] -match "200.+OK") {
121-
if ($host.name -match 'ConsoleHost') {
122-
Invoke-Expression "& curl.exe --insecure --location --output `"$DestinationFullName`" --url `"$SourceUrl`""
118+
119+
Write-Verbose 'Requesing HTTP HEAD to get Content-Length and Accept-Ranges header'
120+
$remote = Invoke-WebRequest -UseBasicParsing -Method Head -Uri $SourceUrl
121+
$remoteLength = $remote.Headers.'Content-Length'
122+
$remoteAcceptsRanges = ($remote.Headers.'Accept-Ranges' | Select-Object -First 1) -eq 'bytes'
123+
124+
$curlCommandExpression = "& curl.exe --insecure --location --output `"$DestinationFullName`" --url `"$SourceUrl`""
125+
126+
if ($host.name -match 'PowerShell ISE Host') {
127+
#PowerShell ISE will display a NativeCommandError, so progress will not be displayed
128+
$Quiet = Invoke-Expression ($curlCommandExpression + ' 2>&1')
129+
}
130+
else {
131+
Invoke-Expression $curlCommandExpression
132+
}
133+
134+
#=================================================
135+
# Continue interrupted download
136+
#=================================================
137+
if (Test-Path $DestinationFullName) {
138+
$localExists = $true
139+
}
140+
141+
$RetryDelaySeconds = 1
142+
$MaxRetryCount = 10
143+
$RetryCount = 0
144+
while (
145+
$localExists `
146+
-and ((Get-Item $DestinationFullName).Length -lt $remoteLength) `
147+
-and $remoteAcceptsRanges `
148+
-and ($RetryCount -lt $MaxRetryCount)
149+
) {
150+
Write-Verbose "Download is incomplete, remote server accepts ranges, will retry in $RetryDelaySeconds second(s)"
151+
Start-Sleep -Seconds $RetryDelaySeconds
152+
$RetryDelaySeconds *= 2 # retry with exponential backoff
153+
$RetryCount += 1
154+
$curlCommandExpression = "& curl.exe --insecure --location --continue-at - --output `"$DestinationFullName`" --url `"$SourceUrl`""
155+
156+
if ($host.name -match 'PowerShell ISE Host') {
157+
#PowerShell ISE will display a NativeCommandError, so progress will not be displayed
158+
$Quiet = Invoke-Expression ($curlCommandExpression + ' 2>&1')
123159
}
124160
else {
125-
#PowerShell ISE will display a NativeCommandError, so progress will not be displayed
126-
$Quiet = Invoke-Expression "& curl.exe --insecure --location --output `"$DestinationFullName`" --url `"$SourceUrl`" 2>&1"
161+
Invoke-Expression $curlCommandExpression
127162
}
128-
} else {
129-
Write-Warning "Header status: $($headers[0])"
163+
}
164+
165+
if ($localExists -and ((Get-Item $DestinationFullName).Length -lt $remoteLength)) {
166+
Write-Verbose "Download is incomplete after $RetryCount retries."
167+
Write-Warning "Could not download $DestinationFullName"
168+
$null
130169
}
131170
}
132171
#=================================================

0 commit comments

Comments
 (0)