Skip to content

Make MSIX removal work under SYSTEM and stop deprovisioned apps returning - #4

Merged
TecharyJames merged 2 commits into
BETAfrom
fix/msix-uninstall-under-system
Sep 19, 2026
Merged

TecharyJames merged 2 commits into
BETAfrom
fix/msix-uninstall-under-system

Conversation

@TecharyJames

@TecharyJames TecharyJames commented Sep 19, 2026 •

Copy link
Copy Markdown
Member

Stacked on #2 (shares Uninstall-TecharyApp.ps1). Base retargets to BETA when #2 merges. Independent of #3.

Two problems, both invisible interactively

Get-AppxPackage without -AllUsers returns only the calling account's packages. SYSTEM has essentially none, so an uninstall pushed from the RMM found nothing and logged "Application 'X' not found on this system" for an app that was installed.

Removing per-user registrations left the provisioned package in place. A provisioned package seeds new user profiles, so the app reappeared for the next user who signed in.

What changed

  • Enumerate and remove with -AllUsers when elevated. SYSTEM is in the Administrators role, so this covers the RMM case.
  • When not elevated, say so and operate per-user. The log states the scope that actually applied instead of implying a machine-wide removal.
  • Remove matching provisioned packages so the app does not return for new profiles.

Neither path is all-or-nothing:

Failure Behaviour
-AllUsers unsupported on this build Retries per-user rather than reporting failure
Provisioned enumeration fails Logged; package removal still proceeds
Not elevated Warns, falls back to current user

Verification

Non-elevated, -WhatIf, against a real package:

Found Modern App: Microsoft.WindowsCalculator (Microsoft.WindowsCalculator_11.2607.0.0_x64__8wekyb3d8bbwe)
[WhatIf] Would remove for the current user only: Microsoft.WindowsCalculator_11.2607.0.0_x64__8wekyb3d8bbwe

A name matching nothing still reports cleanly rather than erroring.

Coverage limitation: this session is not elevated, so the -AllUsers removal and the deprovisioning calls were not executed. Both are guarded by try/catch with a per-user fallback; the enumeration and branching logic is exercised above. Needs one run as SYSTEM against a known MSIX before production use.

…ning

Two problems with the Modern Apps branch of Uninstall-TecharyApp, both of
which only show up in the context the module is actually driven from.

Get-AppxPackage without -AllUsers returns only the calling account's
packages. SYSTEM has essentially none, so an uninstall pushed from an RMM
found nothing and logged "not found on this system" for an app that was
plainly installed. It now enumerates and removes with -AllUsers when
elevated, and says so when it is not, so the log states the scope that
actually applied rather than implying a machine-wide removal.

Removing the per-user registrations also left the provisioned package in
place, and a provisioned package is what seeds new user profiles. The app
therefore reappeared for the next user who signed in. Provisioned packages
matching the name are now removed as well.

Neither path is all-or-nothing: -AllUsers is unsupported on some builds, so
a failure there retries per-user rather than reporting an outright failure,
and provisioning enumeration failing does not stop the package removal.

Verified non-elevated: correct package found, WhatIf reports the honest
scope, and a package that is not installed still reports cleanly. The
elevated -AllUsers and deprovisioning paths are guarded by try/catch with
per-user fallback but were not exercised from this session.
…rror

Validated on a real machine running as SYSTEM. Remove-AppxPackage -AllUsers
works, but two behaviours make a naive reading of it unreliable.

Removal is asynchronous. The package is still listed for a period after the
cmdlet returns, so a check run immediately afterwards reports a failure that
is not real. Confirmation now polls over a 30 second settle window, and a
package still registered at the end is reported as a warning naming a
pending reboot or sign-out, not asserted as a failure.

Get-AppxPackage -AllUsers also lists packages that are merely Staged on the
machine, so presence in that list is not evidence that anyone has the
package installed. Enumeration is filtered to packages actually installed
for at least one user, via PackageUserInformation, so a staged remnant is no
longer treated as something to uninstall.

Test-AppxInstalledForAnyUser falls back to a plain Get-AppxPackage where
per-user information is unavailable, which covers the non-elevated case and
older builds.

Measured under SYSTEM on a real endpoint: Get-AppxPackage sees 69 packages,
Get-AppxPackage -AllUsers sees 197.

Verified: helper returns True for an installed package, False for one that
was removed, and False for a package that does not exist.
@TecharyJames
TecharyJames changed the base branch from fix/api-rate-limit-and-failure-semantics to BETA September 19, 2026 11:48
@TecharyJames
TecharyJames merged commit b5a1d4e into BETA Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant