mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-08-09 09:31:15 +10:00
* Fix installed AppX package detection * Add AppX package restore workflow * Add AppX operation progress feedback * Fix AppX operation launch race * Handle AppX workflow failures
80 lines
3.1 KiB
PowerShell
80 lines
3.1 KiB
PowerShell
function Install-WinUtilAPPX {
|
|
<#
|
|
|
|
.SYNOPSIS
|
|
Registers a local AppX package or installs it from the Microsoft Store
|
|
|
|
.PARAMETER Name
|
|
The AppX package name to install
|
|
|
|
.PARAMETER StoreId
|
|
The optional Microsoft Store product ID used when no local manifest is available
|
|
|
|
#>
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Name,
|
|
|
|
[string]$StoreId
|
|
)
|
|
|
|
Write-WinUtilLog -Component "AppX" -Message "Installing AppX package: $Name"
|
|
|
|
# AppX and DISM cmdlets are more reliable in Windows PowerShell 5.1. Query both installed and
|
|
# provisioned package metadata because either can expose a local manifest that can be registered.
|
|
$ps5Command = {
|
|
$packageName = $args[0]
|
|
$manifestPaths = [System.Collections.Generic.List[string]]::new()
|
|
|
|
Get-AppxPackage -AllUsers -Name $packageName -ErrorAction SilentlyContinue |
|
|
Sort-Object -Property Version -Descending |
|
|
ForEach-Object {
|
|
if (-not [string]::IsNullOrWhiteSpace($_.InstallLocation)) {
|
|
$manifestPaths.Add((Join-Path $_.InstallLocation "AppxManifest.xml"))
|
|
}
|
|
}
|
|
|
|
Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue |
|
|
Where-Object DisplayName -EQ $packageName |
|
|
ForEach-Object {
|
|
if (-not [string]::IsNullOrWhiteSpace($_.InstallLocation)) {
|
|
$manifestPaths.Add((Join-Path $_.InstallLocation "AppxManifest.xml"))
|
|
}
|
|
}
|
|
|
|
$manifestPath = $manifestPaths |
|
|
Select-Object -Unique |
|
|
Where-Object { Test-Path -LiteralPath $_ } |
|
|
Select-Object -First 1
|
|
|
|
if ($null -ne $manifestPath) {
|
|
Add-AppxPackage -Register $manifestPath -DisableDevelopmentMode -ErrorAction Stop
|
|
Write-Output $manifestPath
|
|
}
|
|
}
|
|
|
|
$manifestOutput = powershell.exe -NoProfile -NonInteractive -Command $ps5Command -args $Name 2>&1
|
|
if ($LASTEXITCODE -eq 0 -and $null -ne $manifestOutput) {
|
|
$manifestPath = ($manifestOutput | Select-Object -Last 1).ToString().Trim()
|
|
if (-not [string]::IsNullOrWhiteSpace($manifestPath)) {
|
|
Write-WinUtilLog -Component "AppX" -Message "Registered local AppX manifest for $Name`: $manifestPath"
|
|
return
|
|
}
|
|
}
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
$failureDetails = ($manifestOutput | Out-String).Trim()
|
|
Write-WinUtilLog -Level "WARN" -Component "AppX" -Message "Local AppX registration failed for $Name`: $failureDetails"
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($StoreId)) {
|
|
$errorMessage = "Unable to install $Name because no local manifest or Microsoft Store ID is available."
|
|
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message $errorMessage
|
|
throw $errorMessage
|
|
}
|
|
|
|
Write-WinUtilLog -Component "AppX" -Message "No usable local manifest found for $Name. Installing Microsoft Store product $StoreId."
|
|
Install-WinUtilWinget
|
|
Install-WinUtilProgramWinget -Action Install -Programs @("msstore:$StoreId")
|
|
}
|