private/core-driverpack/Test-OSDCoreDriverPackCloudObject.ps1
|
function Test-OSDCoreDriverPackCloudObject { <# .SYNOPSIS Tests whether an OSDCore driver pack object is available online and ready to downloaded. .DESCRIPTION Reads the Url property from the supplied driver pack object, or from $global:OSDCoreDriverPackCloudObject when no object is supplied, and returns $true when a live TCP connection and HTTP HEAD request can reach it. Returns $false when the object is missing, the Url property is empty, or the URL test fails. HTTP and HTTPS are both tested for host-only web URLs so systems with an invalid date can still detect basic network reachability over HTTP. Specific absolute file URLs are tested exactly as supplied. .PARAMETER DriverPackCloudObject Driver pack object containing a Url property to test. .EXAMPLE Test-OSDCoreDriverPackCloudObject Tests the Url property on $global:OSDCoreDriverPackCloudObject. .EXAMPLE Test-OSDCoreDriverPackCloudObject -DriverPackCloudObject $global:OSDCoreDriverPackCloudObject Tests the Url property on the supplied driver pack object. .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES Author: David Segura - Recast Software 2026-07-19 - Initial private helper created 2026-07-20 - Added live TCP validation before HTTP HEAD to avoid cached success responses #> [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(ValueFromPipeline)] [psobject] $DriverPackCloudObject = $global:OSDCoreDriverPackCloudObject ) process { # The caller may pass an object explicitly or rely on the global OSDCore driver pack selection. if ($null -eq $DriverPackCloudObject) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] OSDCoreDriverPackCloudObject is not set." return $false } # A missing URL means there is nothing useful to test, so return the Boolean failure state. $DriverPackCloudObjectUrl = [string]$DriverPackCloudObject.Url if ([string]::IsNullOrWhiteSpace($DriverPackCloudObjectUrl)) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] OSDCoreDriverPackCloudObject Url is not set." return $false } try { # Build the exact set of URLs to probe before making any web requests. $DriverPackCloudObjectUri = [System.Uri]$DriverPackCloudObjectUrl $IsSpecificAbsoluteUrl = $DriverPackCloudObjectUri.IsAbsoluteUri -and -not [string]::IsNullOrWhiteSpace($DriverPackCloudObjectUri.AbsolutePath) -and $DriverPackCloudObjectUri.AbsolutePath -ne '/' if ($DriverPackCloudObjectUri.IsAbsoluteUri -and ($DriverPackCloudObjectUri.Scheme -notin @('http', 'https') -or $IsSpecificAbsoluteUrl)) { # Non-web absolute URIs and specific file URLs are tested as provided. $RequestUris = @($DriverPackCloudObjectUri) } else { if ($DriverPackCloudObjectUri.IsAbsoluteUri) { # Host-only web URLs are checked over HTTPS first, then HTTP as a fallback for bad system time. $UriBuilder = New-Object System.UriBuilder $DriverPackCloudObjectUri $UriBuilder.Scheme = 'https' $UriBuilder.Port = -1 $HttpsUri = $UriBuilder.Uri $UriBuilder.Scheme = 'http' $UriBuilder.Port = -1 $HttpUri = $UriBuilder.Uri } else { # Bare URLs are expanded to both HTTPS and HTTP targets. $HttpsUri = [System.Uri]::new("https://$($DriverPackCloudObjectUri.OriginalString)") $HttpUri = [System.Uri]::new("http://$($DriverPackCloudObjectUri.OriginalString)") } $RequestUris = @($HttpsUri, $HttpUri) } } catch { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] OSDCoreDriverPackCloudObject Url is not valid: $DriverPackCloudObjectUrl" return $false } $InvokeWebRequestCommand = Get-Command Invoke-WebRequest $Results = foreach ($RequestUri in $RequestUris) { if ($RequestUri.Scheme -in @('http', 'https')) { $RequestPort = $RequestUri.Port if ($RequestUri.IsDefaultPort) { if ($RequestUri.Scheme -eq 'https') { $RequestPort = 443 } else { $RequestPort = 80 } } $TcpClient = New-Object System.Net.Sockets.TcpClient try { $ConnectTask = $TcpClient.ConnectAsync($RequestUri.DnsSafeHost, $RequestPort) if (-not $ConnectTask.Wait(15000) -or -not $TcpClient.Connected) { throw "TCP connection failed." } } catch { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] OSDCoreDriverPackCloudObject TCP FAIL: $RequestUri" [pscustomobject]@{ Uri = $RequestUri Success = $false } continue } finally { $TcpClient.Close() } } # Use HEAD to validate reachability without downloading the driver pack payload. $Params = @{ Method = 'Head' Uri = $RequestUri Headers = @{'Cache-Control'='no-cache, no-store'; 'Pragma'='no-cache'} ErrorAction = 'Stop' } # Keep the request compatible across Windows PowerShell and newer PowerShell versions. if ($InvokeWebRequestCommand.Parameters.ContainsKey('UseBasicParsing')) { $Params['UseBasicParsing'] = $true } if ($InvokeWebRequestCommand.Parameters.ContainsKey('TimeoutSec')) { $Params['TimeoutSec'] = 15 } if ($InvokeWebRequestCommand.Parameters.ContainsKey('DisableKeepAlive')) { $Params['DisableKeepAlive'] = $true } $PreviousCachePolicy = [System.Net.WebRequest]::DefaultCachePolicy try { [System.Net.WebRequest]::DefaultCachePolicy = New-Object System.Net.Cache.RequestCachePolicy ([System.Net.Cache.RequestCacheLevel]::NoCacheNoStore) Invoke-WebRequest @Params | Out-Null Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] OSDCoreDriverPackCloudObject URL OK: $RequestUri" [pscustomobject]@{ Uri = $RequestUri Success = $true } } catch { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] OSDCoreDriverPackCloudObject URL FAIL: $RequestUri" [pscustomobject]@{ Uri = $RequestUri Success = $false } } finally { [System.Net.WebRequest]::DefaultCachePolicy = $PreviousCachePolicy } } # If only HTTP succeeds, the network may be reachable but HTTPS can fail because the clock is wrong. $HttpsResult = $Results | Where-Object { $_.Uri.Scheme -eq 'https' } | Select-Object -First 1 $HttpResult = $Results | Where-Object { $_.Uri.Scheme -eq 'http' } | Select-Object -First 1 if ($HttpsResult -and $HttpResult -and -not $HttpsResult.Success -and $HttpResult.Success) { Write-Warning "HTTPS connection failed for $($HttpsResult.Uri), but HTTP connection succeeded for $($HttpResult.Uri). Check the system date and time." } # Return true when any attempted URL succeeds. [bool]($Results | Where-Object { $_.Success } | Select-Object -First 1) } } |