Private/Get-OSDStageCatalogPackages.ps1
|
function Get-OSDStageCatalogPackages { [CmdletBinding(DefaultParameterSetName = 'Uri')] param( [Parameter(Mandatory, ParameterSetName = 'Uri')] [uri]$CatalogUri, [Parameter(Mandatory, ParameterSetName = 'Path')] [string]$CatalogPath, [string[]]$Name ) if ($PSCmdlet.ParameterSetName -eq 'Uri') { $catalog = Get-OSDStageManifest -Uri $CatalogUri $catalogBaseUri = [uri]::new($CatalogUri, '.') $catalogRoot = $null } else { $resolvedCatalogPath = (Resolve-Path -LiteralPath $CatalogPath -ErrorAction Stop).Path $catalog = Get-OSDStageManifest -Path $resolvedCatalogPath $catalogBaseUri = $null $catalogRoot = Split-Path -Path $resolvedCatalogPath -Parent } Assert-OSDStageCatalog -Catalog $catalog $apps = @($catalog.Packages) $canonicalIds = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) $aliasOwners = @{} # App Ids and aliases become cache directory names. Validate the # complete identity graph before resolving a subset or reading manifests. foreach ($app in $apps) { $appId = [string]$app.Id if ([string]::IsNullOrWhiteSpace($appId) -or $appId -notmatch '^[A-Za-z0-9][A-Za-z0-9._-]*$' -or $appId -match '\.\.') { throw "Invalid app Id '$appId' in repository catalog." } if (-not $canonicalIds.Add($appId)) { throw "Duplicate app Id '$appId' in repository catalog." } } foreach ($app in $apps) { $appId = [string]$app.Id $aliases = @( if ($app.PSObject.Properties.Name -contains 'Aliases') { @($app.Aliases) } ) foreach ($aliasValue in $aliases) { $alias = ([string]$aliasValue).Trim() if ([string]::IsNullOrWhiteSpace($alias) -or $alias -notmatch '^[A-Za-z0-9][A-Za-z0-9._-]*$' -or $alias -match '\.\.') { throw "Invalid alias '$alias' for '$appId' in repository catalog." } if ($canonicalIds.Contains($alias)) { throw "Alias '$alias' for '$appId' conflicts with a canonical app Id." } $aliasKey = $alias.ToLowerInvariant() if ($aliasOwners.ContainsKey($aliasKey)) { throw "Alias '$alias' is assigned to both '$($aliasOwners[$aliasKey])' and '$appId'." } $aliasOwners[$aliasKey] = $appId } } if ($Name) { $resolvedNames = @( foreach ($requestedName in $Name) { $requestedKey = ([string]$requestedName).ToLowerInvariant() if ($aliasOwners.ContainsKey($requestedKey)) { [string]$aliasOwners[$requestedKey] } else { [string]$requestedName } } ) $apps = @($apps | Where-Object { $_.Id -in $resolvedNames }) $missing = @($resolvedNames | Where-Object { $_ -notin @($apps.Id) }) if ($missing.Count -gt 0) { throw "Requested app(s) not found in catalog: $($missing -join ', ')" } } $packages = [System.Collections.Generic.List[object]]::new() foreach ($app in $apps) { if (-not $app.Id) { throw 'Catalog app entry must contain Id.' } foreach ($packageRef in @($app.Architectures)) { if (-not $packageRef.Architecture -or -not $packageRef.Manifest) { throw "Catalog package reference for '$($app.Id)' must contain Architecture and Manifest." } if ($PSCmdlet.ParameterSetName -eq 'Uri') { $packageManifestUri = [uri]::new($catalogBaseUri, ([string]$packageRef.Manifest).Replace('\','/')) $packageManifest = Get-OSDStageManifest -Uri $packageManifestUri $packageBaseUri = [uri]::new($packageManifestUri, '.') } else { $packageManifestPath = Join-Path $catalogRoot (([string]$packageRef.Manifest) -replace '/', [IO.Path]::DirectorySeparatorChar) $packageManifest = Get-OSDStageManifest -Path $packageManifestPath $packageRoot = Split-Path -Path $packageManifestPath -Parent } if ([string]$packageManifest.SchemaVersion -ne '2') { throw "Package manifest for '$($app.Id)' must use SchemaVersion 2." } if ([string]$packageManifest.Id -ne [string]$app.Id) { throw "Package manifest Id '$($packageManifest.Id)' does not match catalog Id '$($app.Id)'." } if (([string]$packageManifest.Architecture).ToLowerInvariant() -ne ([string]$packageRef.Architecture).ToLowerInvariant()) { throw "Package manifest architecture '$($packageManifest.Architecture)' does not match catalog architecture '$($packageRef.Architecture)' for '$($app.Id)'." } if ([string]::IsNullOrWhiteSpace([string]$packageManifest.Version)) { throw "Package manifest for '$($app.Id)' must contain Version." } $packageType = if ($packageManifest.PSObject.Properties.Name -contains 'PackageType' -and -not [string]::IsNullOrWhiteSpace([string]$packageManifest.PackageType)) { [string]$packageManifest.PackageType } else { 'App' } if ($packageType -notin @('App','Script','Font','Certificate','Driver')) { throw "Package '$($app.Id)' has unsupported PackageType '$packageType'. Expected App, Script, Font, Certificate or Driver." } $packageType = if ($packageType -ieq 'Script') { 'Script' } elseif ($packageType -ieq 'Font') { 'Font' } elseif ($packageType -ieq 'Certificate') { 'Certificate' } elseif ($packageType -ieq 'Driver') { 'Driver' } else { 'App' } if ($packageType -eq 'Certificate' -and [string]$packageManifest.CertificateStore -notin @('Root','CA')) { throw "Certificate package '$($app.Id)' requires CertificateStore Root or CA." } if (-not $packageManifest.Payload -or [string]$packageManifest.Payload.Sha256 -notmatch '^[A-Fa-f0-9]{64}$') { throw "Package '$($app.Id)' has an invalid SHA-256 archive definition." } $fileName = if ($packageManifest.Payload.FileName) { [string]$packageManifest.Payload.FileName } else { 'Package.zip' } if ($fileName -ne 'Package.zip') { throw "Package '$($app.Id)' must use the fixed archive name Package.zip." } $archive = [ordered]@{ FileName = $fileName Sha256 = [string]$packageManifest.Payload.Sha256 } if ($PSCmdlet.ParameterSetName -eq 'Uri') { $archive.Uri = ([uri]::new($packageBaseUri, $fileName)).AbsoluteUri } else { $archive.SourcePath = Join-Path $packageRoot $fileName } $packages.Add([pscustomobject]@{ Id = [string]$packageManifest.Id Aliases = @( if ($app.PSObject.Properties.Name -contains 'Aliases') { @($app.Aliases | ForEach-Object { ([string]$_).Trim() }) } ) DisplayName = if ($packageManifest.DisplayName) { [string]$packageManifest.DisplayName } else { [string]$packageManifest.Id } Vendor = if ($packageManifest.Vendor) { ([string]$packageManifest.Vendor).Trim() } else { $null } Version = [string]$packageManifest.Version Architecture = [string]$packageManifest.Architecture PackageType = $packageType CertificateStore = if($packageType -eq 'Certificate'){[string]$packageManifest.CertificateStore}else{$null} SuccessCodes = @($packageManifest.SuccessCodes) Payload = [pscustomobject]$archive }) } } [pscustomobject]@{ SchemaVersion = $catalog.SchemaVersion GeneratedAt = $catalog.GeneratedAt Packages = @($packages) } } |