[CmdletBinding(DefaultParameterSetName = "Url")] param( [Parameter(Mandatory = $true, ParameterSetName = "Url")] [string]$Url, [Parameter(Mandatory = $true, ParameterSetName = "Path")] [string]$Path ) $ErrorActionPreference = "Stop" function Fail($Message) { Write-Error $Message exit 1 } $feedSource = $null $feedContent = $null if ($PSCmdlet.ParameterSetName -eq "Url") { $parsedUrl = $null if (-not [System.Uri]::TryCreate($Url, [System.UriKind]::Absolute, [ref]$parsedUrl)) { Fail "Desktop update feed URL is not absolute: $Url" } if ($parsedUrl.Scheme -ne "https") { Fail "Desktop update feed URL must use HTTPS: $Url" } try { $response = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 30 } catch { Fail "Desktop update feed request failed for ${Url}: $($_.Exception.Message)" } if ($response.StatusCode -ne 200) { Fail "Desktop update feed must return HTTP 200. Actual status: $($response.StatusCode)" } $feedSource = $Url $feedContent = $response.Content } else { if (-not (Test-Path -LiteralPath $Path)) { Fail "Desktop update feed file was not found: $Path" } $feedSource = (Resolve-Path -LiteralPath $Path).Path $feedContent = Get-Content -LiteralPath $feedSource -Raw } try { [xml]$xml = $feedContent } catch { Fail "Desktop update feed is not valid XML: $($_.Exception.Message)" } if ($xml.DocumentElement.Name -ne "QSfera") { Fail "Desktop update feed root element must be ." } $requiredElements = @("version", "versionstring", "web", "downloadurl") foreach ($name in $requiredElements) { if ($null -eq $xml.QSfera.$name) { Fail "Desktop update feed is missing <$name>." } } $version = [string]$xml.QSfera.version $versionString = [string]$xml.QSfera.versionstring $web = [string]$xml.QSfera.web $downloadUrl = [string]$xml.QSfera.downloadurl if (-not [string]::IsNullOrWhiteSpace($web)) { $webUri = $null if (-not [System.Uri]::TryCreate($web, [System.UriKind]::Absolute, [ref]$webUri) -or $webUri.Scheme -ne "https") { Fail "Desktop update feed must be an absolute HTTPS URL when present." } } if ([string]::IsNullOrWhiteSpace($version)) { if (-not [string]::IsNullOrWhiteSpace($downloadUrl)) { Fail "Desktop no-update feed must leave empty when is empty." } } else { $parsedVersion = $null if (-not [System.Version]::TryParse($version, [ref]$parsedVersion)) { Fail "Desktop update feed must be parseable as a version number." } if ([string]::IsNullOrWhiteSpace($versionString)) { Fail "Desktop update feed must set when is present." } $downloadUri = $null if (-not [System.Uri]::TryCreate($downloadUrl, [System.UriKind]::Absolute, [ref]$downloadUri) -or $downloadUri.Scheme -ne "https") { Fail "Desktop update feed must be an absolute HTTPS URL when an update is advertised." } if (-not $downloadUri.AbsolutePath.EndsWith(".msi", [System.StringComparison]::OrdinalIgnoreCase)) { Fail "Desktop Windows updater expects an MSI download URL." } } Write-Host "QSfera Desktop update feed validation passed: $feedSource"