Private/Test-PatHttpsAvailability.ps1
|
function Test-PatHttpsAvailability { <# .SYNOPSIS Tests if HTTPS is available for a given HTTP URI. .DESCRIPTION Internal helper function that probes whether a server supports HTTPS connections. Handles PowerShell version differences for certificate validation and uses mutex-based locking for thread safety in PowerShell 5.1. .PARAMETER HttpUri The HTTP URI to test for HTTPS availability. .OUTPUTS System.Boolean Returns $true if HTTPS is available (including when auth is required), $false otherwise. .EXAMPLE Test-PatHttpsAvailability -HttpUri 'http://plex.local:32400' Returns $true if the server responds to HTTPS requests. #> [CmdletBinding()] [OutputType([bool])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [ValidatePattern('^http://')] [string] $HttpUri ) process { $httpsUri = $HttpUri -replace '^http://', 'https://' Write-Verbose "Checking if HTTPS is available at $httpsUri" $httpsAvailable = $false $certValidationCallback = $null $certCallbackChanged = $false $certMutex = $null try { $testUri = Join-PatUri -BaseUri $httpsUri -Endpoint '/' # Build request params - handle certificate skip for PS version compatibility $requestParams = @{ Uri = $testUri TimeoutSec = 5 ErrorAction = 'Stop' } # Skip certificate validation for self-signed certs (common with Plex) if ($PSVersionTable.PSVersion.Major -ge 6) { # PowerShell 6.0+ supports SkipCertificateCheck parameter $requestParams['SkipCertificateCheck'] = $true } else { # PowerShell 5.1 requires ServerCertificateValidationCallback # Use a named mutex to prevent race conditions when multiple calls modify the global callback $certMutex = [System.Threading.Mutex]::new($false, 'Global\PlexAutomationToolkit_CertCallback') $mutexAcquired = $certMutex.WaitOne(10000) # 10 second timeout if (-not $mutexAcquired) { # Could not acquire mutex - skip HTTPS check rather than risk race condition Write-Verbose "Could not acquire certificate callback mutex, skipping HTTPS availability check" $certMutex.Dispose() $certMutex = $null return $false } else { $certValidationCallback = [System.Net.ServicePointManager]::ServerCertificateValidationCallback [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } $certCallbackChanged = $true } } # Only proceed with HTTPS check if we either have PS6+ or successfully acquired mutex if ($PSVersionTable.PSVersion.Major -ge 6 -or $certCallbackChanged) { $null = Invoke-RestMethod @requestParams $httpsAvailable = $true } } catch { # 401/403 means HTTPS works, just needs auth - that's fine if ($_.Exception.Response.StatusCode.value__ -in @(401, 403)) { $httpsAvailable = $true } else { Write-Verbose "HTTPS not available: $($_.Exception.Message)" } } finally { # Restore original certificate validation callback if we changed it if ($certCallbackChanged) { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $certValidationCallback } # Release mutex if acquired if ($certMutex) { $certMutex.ReleaseMutex() $certMutex.Dispose() } } return $httpsAvailable } } |