#Requires -Version 5.0 # Offline regression tests. BITS and URL resolution are mocked. $ErrorActionPreference = 'Stop' $DownloadToolsPath = Join-Path (Split-Path $PSScriptRoot -Parent) 'Tools.ps1' $DownloadTokens = $null $DownloadParseErrors = $null $DownloadAst = [Management.Automation.Language.Parser]::ParseFile($DownloadToolsPath, [ref]$DownloadTokens, [ref]$DownloadParseErrors) If ($DownloadParseErrors.Count) { Throw ($DownloadParseErrors | Out-String) } Foreach ($DownloadFunctionName in @('Download-File','Download-FileDirectly')) { $DownloadDefinition = $DownloadAst.Find({ param($Node) $Node -is [Management.Automation.Language.FunctionDefinitionAst] -and $Node.Name -eq $DownloadFunctionName }, $true) If (!$DownloadDefinition) { Throw "Missing helper: $DownloadFunctionName" } . ([scriptblock]::Create($DownloadDefinition.Extent.Text)) } Function Get-AbsoluteURI { param($URL) If ($script:DownloadRejectPreflight) { Throw 'Direct download must not resolve the URL first.' } Return $URL } Function IsURLValid { Throw 'Direct download must not make a preliminary validation request.' } Function Get-TempPath { Return ($script:DownloadTestRoot + '\') } Function Start-BitsTransfer { [CmdletBinding()] param($Source, $Destination) $script:DownloadRecordedSource = $Source If ($script:DownloadTestMode -eq 'success') { [IO.File]::WriteAllText($Destination, 'Synthetic download.') Return } [IO.File]::WriteAllBytes($Destination, [byte[]]@()) If ($script:DownloadTestMode -eq 'terminating-error') { Throw 'Synthetic BITS connection failure.' } Microsoft.PowerShell.Utility\Write-Error 'Synthetic BITS TLS failure.' } $DownloadTestRoot = Join-Path ([IO.Path]::GetTempPath()) ('download-file-tests-' + [guid]::NewGuid().ToString('N')) $null = New-Item -Path $DownloadTestRoot -ItemType Directory Try { Foreach ($DownloadFunctionName in @('Download-File','Download-FileDirectly')) { $script:DownloadRejectPreflight = ($DownloadFunctionName -eq 'Download-FileDirectly') $DownloadTestFile = Join-Path $DownloadTestRoot 'collector $test.exe' [IO.File]::WriteAllBytes($DownloadTestFile, [byte[]]@()) $script:DownloadTestMode = 'success' $DownloadTestUrl = 'https://example.invalid/collector.exe?token=original' $DownloadResult = @(& $DownloadFunctionName -URL $DownloadTestUrl -File $DownloadTestFile) If ($DownloadResult.Count -ne 1 -or $DownloadResult[0] -cne $DownloadTestFile -or [IO.File]::ReadAllText($DownloadResult[0]) -cne 'Synthetic download.' -or $script:DownloadRecordedSource -cne $DownloadTestUrl) { Throw 'Successful download must pass the source URL intact, replace an empty file, and return exactly one completed path.' } Write-Host "PASS: ${DownloadFunctionName}: URL forwarding, empty destination overwrite, and one completed path." $DownloadAutomaticFile = Join-Path $DownloadTestRoot 'collector.msi' Foreach ($DownloadBinding in @('positional','pipeline')) { $DownloadResult = @(If ($DownloadBinding -eq 'positional') { & $DownloadFunctionName 'https://example.invalid/collector.msi' } Else { 'https://example.invalid/collector.msi' | & $DownloadFunctionName }) If ($DownloadResult.Count -ne 1 -or $DownloadResult[0] -cne $DownloadAutomaticFile -or [IO.File]::ReadAllText($DownloadAutomaticFile) -cne 'Synthetic download.') { Throw "Automatic filename or $DownloadBinding URL binding failed." } } Write-Host "PASS: ${DownloadFunctionName}: positional/pipeline URL and automatic filename with extension." Foreach ($script:DownloadTestMode in @('nonterminating-error','terminating-error')) { # Match an RMM that uses the normal Continue preference and does not pass -ErrorAction. $ErrorActionPreference = 'Continue' $DownloadCaught = $null $DownloadReturnedPaths = @() Try { & $DownloadFunctionName -URL 'https://example.invalid/collector.exe' -File $DownloadTestFile | ForEach-Object { $DownloadReturnedPaths += $_ } } Catch { $DownloadCaught = $_ } Finally { $ErrorActionPreference = 'Stop' } If ($null -eq $DownloadCaught -or $DownloadCaught.Exception.Message -notlike '*Synthetic BITS*failure*') { Throw 'Failed transfer must throw and preserve the BITS error.' } If ($DownloadReturnedPaths.Count -ne 0) { Throw 'Failed transfer returned a success path.' } Write-Host "PASS: ${DownloadFunctionName}: $script:DownloadTestMode stops the caller and preserves the transfer error." } } Write-Host "All download helper tests passed on PowerShell $($PSVersionTable.PSVersion), $([IntPtr]::Size * 8)-bit." } Finally { $DownloadResolvedRoot = (Resolve-Path -LiteralPath $DownloadTestRoot).Path $DownloadTempRoot = [IO.Path]::GetFullPath([IO.Path]::GetTempPath()).TrimEnd('\') + '\' If (!$DownloadResolvedRoot.StartsWith($DownloadTempRoot, [StringComparison]::OrdinalIgnoreCase) -or (Split-Path $DownloadResolvedRoot -Leaf) -notlike 'download-file-tests-*') { Throw 'Unexpected cleanup directory.' } Remove-Item -LiteralPath $DownloadResolvedRoot -Recurse -Force }