diff --git a/src/windows-dev-config/README.md b/src/windows-dev-config/README.md index ade4f72b..0242e4d4 100644 --- a/src/windows-dev-config/README.md +++ b/src/windows-dev-config/README.md @@ -465,6 +465,8 @@ The setup targets the public stable release pinned in [`steps/_winget.ps1`](step The step is best-effort, so a machine that can't be updated is flagged rather than stopped, and the rest of the run continues on whatever winget it has. +Setup reuses installed dependencies that meet the required version for the same package name, publisher, and architecture. + An installed version equal to or newer than the pin skips the update without a network lookup. RPC recovery re-registers the installed App Installer package locally, then retries the package query; it does not download or downgrade a newer version. To change the target release, update `DevConfigWinGetTargetVersion` and both asset hashes in `steps/_winget.ps1` together, then sign and publish the payload as usual. diff --git a/src/windows-dev-config/steps/_winget.ps1 b/src/windows-dev-config/steps/_winget.ps1 index babf6579..870bf366 100644 --- a/src/windows-dev-config/steps/_winget.ps1 +++ b/src/windows-dev-config/steps/_winget.ps1 @@ -109,7 +109,31 @@ function Invoke-DevConfigWinGetDeployment { } ) $bundle = Join-Path $Directory 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle' - Add-AppxPackage -Path $bundle -DependencyPath $dependencies -ForceTargetApplicationShutdown -ErrorAction Stop + Add-Type -AssemblyName System.IO.Compression.FileSystem + $dependencies = @( + foreach ($dependency in $dependencies) { + $archive = [IO.Compression.ZipFile]::OpenRead($dependency) + try { + $entry = $archive.GetEntry('AppxManifest.xml') + if (-not $entry) { throw "Missing AppxManifest.xml in $dependency." } + $reader = [IO.StreamReader]::new($entry.Open()) + try { $manifest = [xml]$reader.ReadToEnd() } finally { $reader.Dispose() } + } finally { $archive.Dispose() } + $identity = $manifest.Package.Identity + if (-not $identity.Name -or -not $identity.Publisher -or -not $identity.ProcessorArchitecture -or -not $identity.Version) { + throw "Incomplete dependency identity in $dependency." + } + $installed = @(Get-AppxPackage -Name $identity.Name -ErrorAction Stop | Where-Object { + $_.Publisher -eq $identity.Publisher -and + [string]$_.Architecture -eq $identity.ProcessorArchitecture -and + [version]$_.Version -ge [version]$identity.Version + }) + if (-not $installed.Count) { $dependency } + } + ) + $parameters = @{ Path = $bundle; ForceTargetApplicationShutdown = $true; ErrorAction = 'Stop' } + if ($dependencies.Count) { $parameters.DependencyPath = $dependencies } + Add-AppxPackage @parameters } else { $package = Get-AppxPackage -Name Microsoft.DesktopAppInstaller | Sort-Object Version -Descending | Select-Object -First 1 @@ -125,7 +149,7 @@ function Invoke-DevConfigWinGetDeployment { } exit 0 } catch { - [Console]::Error.WriteLine($_.ToString()) + Write-Error -ErrorRecord $_ -ErrorAction Continue exit 1 } } @@ -173,7 +197,7 @@ function Confirm-DevConfigWinGetReady { try { Get-WinGetPackage -Source winget -ErrorAction Stop | Out-Null return - } catch [System.Runtime.InteropServices.COMException] { + } catch { # 0x800706BA means the module could not reach WinGet's RPC server. if ($_.Exception.HResult -ne -2147023174) { throw } $moduleError = $_.Exception.Message