private/WinPEDrivers/CloudWinPEDriver/Invoke-CloudWinPEDriverDownload.ps1
|
#Requires -PSEdition Core function Invoke-CloudWinPEDriverDownload { <# .SYNOPSIS Downloads a WinPE driver file using curl.exe with SHA256 verification. .DESCRIPTION Internal helper used by all per-driver Save-CloudWinPEDriver* functions. Uses curl.exe for reliable binary downloads. Skips the download when the file already exists and the SHA256 checksum matches. Throws a terminating error on download failure or checksum mismatch so callers can catch cleanly. .PARAMETER Uri The download URI. .PARAMETER DestinationPath Full path (including filename) where the file will be saved. .PARAMETER SearchUri Optional referer URI sent with the curl request. .PARAMETER ExpectedSHA256 Expected SHA256 hash. When provided and the file already exists with a matching hash, the download is skipped entirely. .PARAMETER Force Re-download even if the file already exists and the hash matches. .OUTPUTS [System.IO.FileInfo] The downloaded (or already-cached) file. #> [CmdletBinding()] [OutputType([System.IO.FileInfo])] param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Uri, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$DestinationPath, [Parameter()] [string]$SearchUri, [Parameter()] [string]$ExpectedSHA256, [Parameter()] [switch]$Force ) $downloadDir = Split-Path -Path $DestinationPath -Parent $destinationLeaf = Split-Path -Path $DestinationPath -Leaf $normalizedExpectedSHA256 = $null if (-not (Test-Path -Path $downloadDir)) { New-Item -ItemType Directory -Path $downloadDir -Force | Out-Null } if (-not [string]::IsNullOrWhiteSpace($ExpectedSHA256)) { $normalizedExpectedSHA256 = ($ExpectedSHA256 -replace '\s+', '').ToUpperInvariant() } $getVerifiedCachedFile = { param([string]$Path) if (-not (Test-Path -Path $Path -PathType Leaf)) { return $null } if (-not $normalizedExpectedSHA256) { return Get-Item -Path $Path } $actualHash = (Get-FileHash -Path $Path -Algorithm SHA256).Hash.ToUpperInvariant() if ($actualHash -eq $normalizedExpectedSHA256) { return Get-Item -Path $Path } return $null } # Skip if file already exists and hash matches if (-not $Force) { $verifiedCachedFile = & $getVerifiedCachedFile $DestinationPath if ($verifiedCachedFile) { if ($normalizedExpectedSHA256) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] '$destinationLeaf' already downloaded and SHA256 verified. Skipping." } else { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] '$destinationLeaf' already exists (no checksum to verify). Skipping." } return $verifiedCachedFile } if ($normalizedExpectedSHA256) { $alternateCachedFile = Get-ChildItem -Path $downloadDir -File -ErrorAction SilentlyContinue | Where-Object { $_.FullName -ne $DestinationPath } | ForEach-Object { $cachedFile = & $getVerifiedCachedFile $_.FullName if ($cachedFile) { $cachedFile } } | Select-Object -First 1 if ($alternateCachedFile) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Reusing cached file '$($alternateCachedFile.Name)' for '$destinationLeaf'." Copy-Item -Path $alternateCachedFile.FullName -Destination $DestinationPath -Force return Get-Item -Path $DestinationPath } if (Test-Path -Path $DestinationPath -PathType Leaf) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] SHA256 mismatch for '$destinationLeaf'. Re-downloading." } } } Write-OSDeployWinPEDriversProgress -Message "Source: $Uri" Write-OSDeployWinPEDriversProgress -Message "Output: $DestinationPath" Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Downloading '$(Split-Path $Uri -Leaf)'" $curlArgs = @( '--location', '--fail', '--retry', '3', '--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36' ) if ($SearchUri) { $curlArgs += '--referer', $SearchUri } $curlArgs += '--output', $DestinationPath, $Uri curl.exe @curlArgs if ($LASTEXITCODE -ne 0) { $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.IO.IOException]::new("curl.exe failed (exit $LASTEXITCODE) downloading '$Uri'"), 'DownloadFailed', [System.Management.Automation.ErrorCategory]::ConnectionError, $Uri ) ) } if ($normalizedExpectedSHA256) { $actualHash = (Get-FileHash -Path $DestinationPath -Algorithm SHA256).Hash.ToUpperInvariant() if ($actualHash -ne $normalizedExpectedSHA256) { Remove-Item -Path $DestinationPath -Force -ErrorAction SilentlyContinue $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.IO.IOException]::new("SHA256 mismatch for '$destinationLeaf'. Expected: $normalizedExpectedSHA256, Actual: $actualHash"), 'ChecksumMismatch', [System.Management.Automation.ErrorCategory]::SecurityError, $DestinationPath ) ) } Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] SHA256 verified for '$destinationLeaf'" } Get-Item -Path $DestinationPath } |