Private/Invoke-ADTWebDownload.ps1
#----------------------------------------------------------------------------- # # MARK: Invoke-ADTWebDownload # #----------------------------------------------------------------------------- function Invoke-ADTWebDownload { <# .SYNOPSIS Wraps around Invoke-WebRequest to provide logging and retry support. .DESCRIPTION This function allows callers to download files as part of a deployment with logging and retry support. .PARAMETER Uri The URL that to retrieve the file from. .PARAMETER OutFile The path of where to save the file to. .PARAMETER Headers Any headers that need to be provided for file transfer. .PARAMETER Sha256Hash An optional SHA256 reference file hash for download verification. .PARAMETER PassThru Returns the WebResponseObject object from Invoke-WebRequest. .INPUTS None You cannot pipe objects to this function. .OUTPUTS Microsoft.PowerShell.Commands.WebResponseObject Invoke-ADTWebDownload returns the results from Invoke-WebRequest if PassThru is specified. .EXAMPLE Invoke-ADTWebDownload -Uri https://aka.ms/getwinget -OutFile "$($adtSession.DirSupportFiles)\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" Downloads the latest WinGet installer to the SupportFiles directory. .LINK https://github.com/mjr4077au/PSAppDeployToolkit.WinGet #> [CmdletBinding()] [OutputType([Microsoft.PowerShell.Commands.WebResponseObject])] param ( [Parameter(Mandatory = $true)] [ValidateScript({ if (![System.Uri]::IsWellFormedUriString($_.AbsoluteUri, [System.UriKind]::Absolute)) { $PSCmdlet.ThrowTerminatingError((New-ADTValidateScriptErrorRecord -ParameterName Uri -ProvidedValue $_ -ExceptionMessage 'The specified input is not a valid Uri.')) } return !!$_ })] [System.Uri]$Uri, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String]$OutFile, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [System.Collections.IDictionary]$Headers = @{ Accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' }, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [System.String]$Sha256Hash, [Parameter(Mandatory = $false)] [System.Management.Automation.SwitchParameter]$PassThru ) begin { # Initialize function. Initialize-ADTFunction -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } process { try { try { # Commence download and return the result if passing through. Write-ADTLogEntry -Message "Downloading $Uri." $iwrParams = Get-ADTBoundParametersAndDefaultValues -Invocation $MyInvocation -Exclude Sha256Hash $iwrResult = Invoke-ADTCommandWithRetries -Command $Script:CommandTable.'Invoke-WebRequest' -UseBasicParsing @iwrParams -Verbose:$false # Validate the hash if one was provided. if ($PSBoundParameters.ContainsKey('Sha256Hash') -and (($fileHash = Get-FileHash -LiteralPath $OutFile).Hash -ne $Sha256Hash)) { $naerParams = @{ Exception = [System.BadImageFormatException]::new("The downloaded file has an invalid file hash of [$($fileHash.Hash)].", $OutFile) Category = [System.Management.Automation.ErrorCategory]::InvalidData ErrorId = 'DownloadedFileInvalid' TargetObject = $fileHash RecommendedAction = "Please compare the downloaded file's hash against the provided value and try again." } throw (New-ADTErrorRecord @naerParams) } # Return any results from Invoke-WebRequest if we have any and we're passing through. if ($PassThru -and $iwrResult) { return $iwrResult } } catch { # Re-writing the ErrorRecord with Write-Object ensures the correct PositionMessage is used. Write-Error -ErrorRecord $_ } } catch { # Process the caught error, log it and throw depending on the specified ErrorAction. Invoke-ADTFunctionErrorHandler -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState -ErrorRecord $_ -LogMessage "Error downloading setup file(s) from the provided URL of [$Uri]." } } end { # Finalize function. Complete-ADTFunction -Cmdlet $PSCmdlet } } |