Private/Get-YAMLInstallerInfo.ps1
|
function Get-YAMLInstallerInfo { <# .SYNOPSIS Parses a winget manifest SET into the installer/package facts the toolkit needs. .DESCRIPTION A winget package ships SEVERAL manifests and they do NOT hold the same keys: *.installer.yaml InstallerType, Architecture, ProductCode, Scope, InstallerLocale, InstallerSwitches/Silent <- the installer data, nowhere else *.locale*.yaml PackageName, Publisher, ShortDescription, PackageUrl, PublisherUrl <id>.yaml PackageIdentifier, PackageVersion This used to read `Get-ChildItem '*.yaml'`[0] — whatever sorted first alphabetically, typically the LOCALE manifest — and so returned $null for every installer field. Each field group is now read from the manifest that owns it (Get-WingetManifestFile), with a fall back to the other manifests so a folder holding a single hand-made manifest still parses exactly as before. Manifests are UTF-8: read with -Encoding UTF8 or non-ASCII publisher/app names get mangled. .OUTPUTS Hashtable of the parsed fields, or $null when the folder holds no manifest / cannot be parsed. #> [CmdletBinding()] [OutputType([hashtable])] param([string]$FilesPath) $installerFile = Get-WingetManifestFile -Path $FilesPath -Kind Installer if (-not $installerFile) { return $null } try { # Installer facts: ONLY from the installer manifest (a locale manifest has none of them, and # anything that looks like one there is not the installer's). $yamlContent = Get-Content -LiteralPath $installerFile.FullName -Raw -Encoding UTF8 # Package/display facts: locale manifest first, then the version manifest, then the installer # manifest as a last resort (single-manifest folders). Concatenated in that preference order so # the existing regexes — unchanged — hit the owning manifest's value first. $metaContent = '' $seen = @{} foreach ($f in @( (Get-WingetManifestFile -Path $FilesPath -Kind Locale), (Get-WingetManifestFile -Path $FilesPath -Kind Version), $installerFile)) { if ($f -and -not $seen.ContainsKey($f.FullName)) { $seen[$f.FullName] = $true $metaContent += (Get-Content -LiteralPath $f.FullName -Raw -Encoding UTF8) + "`n" } } $installerInfo = @{ PackageIdentifier = $null PackageName = $null Publisher = $null PackageVersion = $null Architecture = $null SilentArgs = $null ProductCode = $null Scope = $null InstallerType = $null InstallerLocale = $null Description = $null InformationUrl = $null } # PackageIdentifier appears in EVERY manifest in the set (installer, version and locale), so either # source is valid — prefer the installer manifest, fall back to the metadata ones. if ($yamlContent -match '(?m)^\s*PackageIdentifier:\s*(.+)') { $installerInfo.PackageIdentifier = $matches[1].Trim() } elseif ($metaContent -match '(?m)^\s*PackageIdentifier:\s*(.+)') { $installerInfo.PackageIdentifier = $matches[1].Trim() } # Parse basic package info if ($metaContent -match '(?m)^\s*PackageName:\s*(.+)') { $installerInfo.PackageName = $matches[1].Trim() } if ($metaContent -match '(?m)^\s*Publisher:\s*(.+)') { $installerInfo.Publisher = $matches[1].Trim() } if ($metaContent -match '(?m)^\s*PackageVersion:\s*(.+)') { $installerInfo.PackageVersion = $matches[1].Trim() } # These live in the INSTALLER manifest, where they are frequently the first key of a YAML list # item under `Installers:` — i.e. ` - Architecture: x64`. The anchor must therefore allow an # optional list dash between the leading whitespace and the key, or `^\s*Architecture` never matches # the dashed form and the field comes back empty. if ($yamlContent -match '(?m)^\s*-?\s*Architecture:\s*(.+)') { $installerInfo.Architecture = $matches[1].Trim() } if ($yamlContent -match '(?m)^\s*-?\s*ProductCode:\s*(.+)') { $installerInfo.ProductCode = $matches[1].Trim() } if ($yamlContent -match '(?m)^\s*-?\s*Scope:\s*(.+)') { $installerInfo.Scope = $matches[1].Trim().ToLowerInvariant() } if ($yamlContent -match '(?m)^\s*-?\s*InstallerType:\s*(\S+)') { $installerInfo.InstallerType = $matches[1].Trim().ToLowerInvariant() } if ($yamlContent -match '(?m)^\s*-?\s*InstallerLocale:\s*(\S+)') { $installerInfo.InstallerLocale = $matches[1].Trim() } # Parse installer switches (Silent: may appear after other keys under InstallerSwitches:) if ($yamlContent -match '(?s)InstallerSwitches:.*?\n\s+Silent:\s*([^\n]+)') { $installerInfo.SilentArgs = $matches[1].Trim() } # Description and information URL (used for the Intune app shell) if ($metaContent -match '(?m)^\s*ShortDescription:\s*(.+)') { $installerInfo.Description = $matches[1].Trim() } elseif ($metaContent -match '(?m)^\s*Description:\s*(.+)') { $installerInfo.Description = $matches[1].Trim() } if ($metaContent -match '(?m)^\s*PackageUrl:\s*(.+)') { $installerInfo.InformationUrl = $matches[1].Trim() } elseif ($metaContent -match '(?m)^\s*PublisherUrl:\s*(.+)') { $installerInfo.InformationUrl = $matches[1].Trim() } return $installerInfo } catch { Write-Warning "Failed to parse YAML file: $($_.Exception.Message)" return $null } } |