From 5bb13e34f8de2e2a7ba943ff72b12c0569435e62 Mon Sep 17 00:00:00 2001 From: undergroundwires Date: Fri, 3 Nov 2023 15:24:15 +0100 Subject: [PATCH] win: fix store revert for multiple installs #260 This commit improves the revert script for store apps to handle scenarios where `Get-AppxPackage` returns multiple packages. Instead of relying on a single package result, the script now iterates over all found packages and attempts installation using the `AppxManifest.xml` for each. This ensures that even if multiple versions or instances of a package are found, the script will robustly handle and attempt to install each one until successful. Other changes: - Add better message with suggestion if the revert code fails, as discussed in #270. - Improve robustness of finding manifest path by using `Join-Path` instead of basic string concatenation. This resolves wrong paths being built due to missing `\` in file path. - Add check for null or empty `InstallLocation` before accessing manifest path. It prevents errors when accessing `AppxManifest.xml`, enhancing script robustness and reliability. - Improve error handling in manifest file existence check with try-catch block to catch and log exceptions, ensuring uninterrupted script execution in edge cases such as when the script lacks access to read the directory. - Add verification of package installation before attempting to install the package for increased robustness. - Add documentation for revertCode. --- src/application/collections/windows.yaml | 63 ++++++++++++++++++------ 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/src/application/collections/windows.yaml b/src/application/collections/windows.yaml index 0fbad3b2..166ae05d 100644 --- a/src/application/collections/windows.yaml +++ b/src/application/collections/windows.yaml @@ -10247,24 +10247,55 @@ functions: codeComment: Uninstall '{{ $packageName }}' Microsoft Store app. code: Get-AppxPackage '{{ $packageName }}' | Remove-AppxPackage # This script attempts to reinstall the app that was just uninstalled, if necessary. - # The app's package family name is constructed using its name and publisher ID. - # Package Family Name is: `_` - # Learn more about package identity: https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/package-identity-overview#publisher-id (https://archive.ph/Sx4JC) + # Re-installation strategy: + # 1. Attempt to locate the package from another user's installation: + # - Utilizes the `Get-AppxPackage` command with the `-AllUsers` flag to search across all user installations. + # - Iterates through the results to locate the manifest file required for re-installation. + # 2. Attempt to locate the package from the system installation: + # - Utilizes the `Get-AppxPackage` command with `-RegisterByFamilyName` to search for the manifest file in the system installation. + # - The app's package family name is constructed using its name and publisher ID. + # Package Family Name is: `_` + # Learn more about package identity: https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/package-identity-overview#publisher-id (https://archive.ph/Sx4JC) + # - Based on tests, Windows attempts to locate the file in the installation location of the package. + # This location can be identified using commands such as `(Get-AppxPackage -AllUsers 'Windows.PrintDialog').InstallLocation`. + # Possible installation locations include: + # - `%WINDIR%\SystemApps\{PackageFamilyName}` (for system apps) + # - `%WINDIR%\{ShortAppName}` (for system apps) + # - `%SYSTEMDRIVE%\Program Files\WindowsApps\{PackageName}` (for non-system apps) + # View all package locations: `Get-AppxPackage | Sort Name | Format-Table Name, InstallLocation` revertCodeComment: Reinstall '{{ $packageName }}' if it was previously uninstalled. revertCode: |- $packageName='{{ $packageName }}' $publisherId='{{ $publisherId }}' + if (Get-AppxPackage -Name $packageName) { + Write-Host "Skipping, `"$packageName`" is already installed for the current user." + exit 0 + } Write-Host "Starting the installation process for `"$packageName`"..." - # Attempting installation using the manifest file + # Attempt installation using the manifest file Write-Host "Checking if `"$packageName`" is installed on another user profile..." - $package = Get-AppxPackage -AllUsers $packageName - if (!$package) { + $packages = @(Get-AppxPackage -AllUsers $packageName) + if (!$packages) { Write-Host "`"$packageName`" is not installed on any other user profiles." } else { - Write-Host "Found package `"$($package.PackageFullName)`"." - $manifestPath = "$($package.InstallLocation)AppxManifest.xml" - if (Test-Path "$manifestPath") { - Write-Host "Manifest file located. Trying to install using the manifest..." + foreach ($package in $packages) { + Write-Host "Found package `"$($package.PackageFullName)`"." + $installationDir = $package.InstallLocation + if ([string]::IsNullOrWhiteSpace($installationDir)) { + Write-Warning "Installation directory for `"$packageName`" is not found or invalid." + continue + } + $manifestPath = Join-Path -Path $installationDir -ChildPath 'AppxManifest.xml' + try { + if (-Not (Test-Path "$manifestPath")) { + Write-Host "Manifest file not found for `"$packageName`" on another user profile: `"$manifestPath`"." + continue + } + } catch { + Write-Warning "An error occurred while checking for the manifest file: $($_.Exception.Message)" + continue + } + Write-Host "Manifest file located. Trying to install using the manifest: `"$manifestPath`"..." try { Add-AppxPackage -DisableDevelopmentMode -Register "$manifestPath" -ErrorAction Stop Write-Host "Successfully installed `"$packageName`" using its manifest file." @@ -10272,13 +10303,11 @@ functions: } catch { Write-Warning "Error installing from manifest: $($_.Exception.Message)" } - } else { - Write-Host "Manifest file not found for `"$packageName`"." } } - # Attempting installation using the package family name + # Attempt installation using the package family name $packageFamilyName = "$($packageName)_$($publisherId)" - Write-Host "Trying to install `"$packageName`" using its package family name: `"$packageFamilyName`"..." + Write-Host "Trying to install `"$packageName`" using its package family name: `"$packageFamilyName`" from system installation..." try { Add-AppxPackage -RegisterByFamilyName -MainPackage $packageFamilyName -ErrorAction Stop Write-Host "Successfully installed `"$packageName`" using its package family name." @@ -10286,8 +10315,10 @@ functions: } catch { Write-Warning "Error installing using package family name: $($_.Exception.Message)" } - # If all methods fail - throw "Unable to install `"$packageName`". Please check the provided details and try again." + throw "Unable to reinstall the requested package ($packageName). " + ` + "It appears to no longer be included in this version of Windows. " + ` + "You may search for it or an alternative in the Microsoft Store or " + ` + "consider using an earlier version of Windows where this package was originally provided." - function: RunInlineCode # This script prevents specified applications from being automatically reinstalled during Windows updates.