param( [Parameter(Mandatory=$true)] [string]$Url, [Parameter(Mandatory=$true)] [string]$Destination ) $ErrorActionPreference = 'Stop' Write-Host "============================================" Write-Host " Resumable File Download" Write-Host "============================================" Write-Host "" Write-Host "Destination: $Destination" Write-Host "" try { # Check for partial file to resume $startBytes = 0 if (Test-Path $Destination) { $startBytes = (Get-Item $Destination).Length if ($startBytes -gt 0) { Write-Host "Partial file found: $([math]::Round($startBytes / 1MB, 1)) MB already downloaded" Write-Host "Resuming..." Write-Host "" } } # Ensure destination directory exists $destDir = Split-Path $Destination -Parent if ($destDir -and !(Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } # Build headers $headers = @{} if ($startBytes -gt 0) { $headers["Range"] = "bytes=$startBytes-" } # Use Invoke-WebRequest with domain credentials for SharePoint auth $params = @{ Uri = $Url OutFile = $Destination UseDefaultCredentials = $true UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" Headers = $headers UseBasicParsing = $true } # If resuming, we need to handle appending manually if ($startBytes -gt 0) { # Download to a temp file, then append $tempFile = "$Destination.partial" $params.OutFile = $tempFile Write-Host "Downloading..." Invoke-WebRequest @params # Check if we got actual content $tempSize = (Get-Item $tempFile).Length if ($tempSize -eq 0) { Remove-Item $tempFile -Force Write-Host "" Write-Host "WARNING: Server returned 0 bytes. The URL may have expired." Write-Host "Get a fresh SharePoint link and try again." exit 1 } # Append to existing file $existingBytes = [System.IO.File]::ReadAllBytes($Destination) $newBytes = [System.IO.File]::ReadAllBytes($tempFile) $combined = New-Object byte[] ($existingBytes.Length + $newBytes.Length) [System.Buffer]::BlockCopy($existingBytes, 0, $combined, 0, $existingBytes.Length) [System.Buffer]::BlockCopy($newBytes, 0, $combined, $existingBytes.Length, $newBytes.Length) [System.IO.File]::WriteAllBytes($Destination, $combined) Remove-Item $tempFile -Force $totalMB = [math]::Round(($existingBytes.Length + $newBytes.Length) / 1MB, 1) Write-Host "" Write-Host "Download complete: $totalMB MB saved to $Destination" } else { Write-Host "Downloading..." Invoke-WebRequest @params # Verify we got actual content $fileSize = (Get-Item $Destination).Length if ($fileSize -eq 0) { Remove-Item $Destination -Force Write-Host "" Write-Host "WARNING: Downloaded 0 bytes. Possible causes:" Write-Host " - SharePoint URL expired or requires browser login" Write-Host " - URL is a redirect/login page, not the actual file" Write-Host "" Write-Host "Try this: In Edge, start the download, then go to" Write-Host "edge://downloads and copy the source URL from there." exit 1 } $totalMB = [math]::Round($fileSize / 1MB, 1) Write-Host "" Write-Host "Download complete: $totalMB MB saved to $Destination" } } catch { Write-Host "" Write-Host "Error: $_" Write-Host "" if (Test-Path $Destination) { $partialMB = [math]::Round((Get-Item $Destination).Length / 1MB, 1) Write-Host "Partial file kept: $partialMB MB" } Write-Host "Re-run with the same arguments to resume." exit 1 }