MSIX supports installing a package for all users; the formal term is you 'provision' the package. This makes the package available to all users, compared to registering a package for a user. Here's the definitive way to install + uninstall a package 'per user' and 'for all users'. The simple explanation is...
- PerUser: Install=Add, Uninstall=Remove
- AllUsers: Install=Stage+Provision, Uninstall=Deprovision+Remove
For a more detailed explanation keep reading, but remember, you asked :P If your coffee's low I suggest a refill before proceeding...
Here's some code snippets with the key APIs. I'l use C# syntax as I'm not as familiar with pywinrt's projections but that's just syntax. It's the APIs that matter:
Per-User
Install
var options = new Windows.Management.Deployment.AddPackageOptions();
var packageManager = new Windows.Management.Deployment.PackageManager();
var packageUri = new Uri("file://c:/blah/foo.msix");
var result = packageManager.AddPackageByUriAsync(packageUri, options).GetAwaiter();
Uninstall
string packageFullName = "foo_1.2.3.4_neutral__1234567890abc";
Windows.Management.Deployment.PackageManager packageManager;
var result = packageManager.RemovePackageAsync(packageFullName).GetAwaiter();
All Users
Install
var options = new Windows.Management.Deployment.StagePackageOptions();
var packageManager = new Windows.Management.Deployment.PackageManager();
var result = packageManager.StagePackageByUriAsync(packageUri, options).GetAwaiter();
string packageFamilyName = "foo_1234567890abc";
result = packageManager.ProvisionPackageForAllUsersAsync(packageFamilyName);
Uninstall
string packageFamilyName = "foo_1234567890abc";
result = packageManager.DeprovisionPackageForAllUsersAsync(packageFamilyName);
string packageFullName = "foo_1.2.3.4_neutral__1234567890abc";
Windows.Management.Deployment.PackageManager packageManager;
var options = Windows.Management.Deployment.RemovalOptions.RemoveForAllUsers;
var result = packageManager.RemovePackageAsync(packageFullName, options).GetAwaiter();
The APIs have multiple overloads for behavioral variations but this is representative enough.
Explanation
It helps to understand 'install' isn't actually a proper noun for MSIX. To oversimplify...
- Stage = Lay down the package content on the disk appropriately. Suuuuper oversimplistically:
MKDIR pkgdir & UNZIP package.msix to pkgdir & ACL pkgdir
- Register = Wire up the user profile for the package (create tiles on StartMenu, define file type associations, yadda yadda)
Stage is done once per machine, and when complete the files are readable but only the Deployment pipeline has write access. This lets us share the files across all users (no need for unique copies of files).
OTOH Register is a per-user action. To "install" a package for 5 users, ultimately, the package is staged once and registered 5x.
"Add" is a common operation that does both "Stage this package if necessary + Register it for the user".
This requires no special permissions, other than the API is called by a Medium IL process (or an AppContainer with the packageManagement capability).
To 'uninstall' you Remove the package which will Deregister it for the current user and, if there's no other references on the package, it's Destaged (i.e. removed from the system).
Package Lifetime and References
MSIX uses a GC style model for package lifetime. A package can be removed only if there are no 'references' to the package. There's several ways to define a reference e.g. Register'ing a package for a user. If a package is registered for 2 users and one Removes the package it's no longer Registered for that user but can't be removed from disk without breaking the other Registered user. When the 2nd user Removes the package its Deregistered and if that's the last reference on the package it's also automagically removed from disk.
There's several ways a 'reference' can be defined on a package. Register is one. Being listed in the Provisioned list of packages is another. There's a few other ways but this is beyond the scope of this discussion. Just know MSIX uses GC style semantics so packages will be removed from disk when the last reference is removed.
AllUser Explanation
Windows has a list of provision packages, alterable with De/Provision APIs. This list affects more than just the current user so altering it requires admin privilege (aka elevation).
Notice the order of operations. To install we must Stage then Provision because Provision takes a package family name for a package known to Windows at this point. Windows knows about packages once Staged so you can't (successfully) Provision a package before it's Staged (or Added).
Provisioned packages are registered for users at the next opportunity, usually their next login. At login Windows compares what a user has registered vs what the should have e.g. the Provisioned package list has the Foo package but when Bob logs in he doesn't have Foo registered, so Windows registers it for him during his login. This is why Calculator and other provisioned packages show up on everyone's StartMenu despite never having done anything to specifically request installation.
On the flipside, during uninstall we Deprovision the package first, to make sure no new user gets it Registered (i.e. avoid timing/race conditions). Deprovisioning the package removes it from the Provisioned list. That's all. There's no change to user Registration, it's simply no longer in the list so new users don't get it offered to them.
Then once Deprovisioned we call Remove with the RemoveForAllUsers option. This deregisters the package for the current user, and other users logged in. IF a package is registered for a user and they're not logged in, the remove request is tracked for that user and processed when they next login.*
* Registering a package requires a user be logged in because various resources and APIs used during registration are only available and functional while the user's logged in. And for those thinking of HKCU yes that's one reason, but the simplest one. There's other more complex interactions which can't be done without the user being logged in.
Powershell Cmdlets
You can do this via the command line using Powershell cmdlets
Per-User
Install
Add-AppxPackage c:\blah\foo.msix
Uninstall
Get-AppxPackage foo | Remove-AppxPackage
All Users
Install
Add-AppxProvisionedPackage -Online -PackagePath c:\blah\foo.msix
Uninstall
Remove-AppxProvisionedPackage -Online -PackageName Foo -AllUsers
The *-AppxProvisionedPackage cmdlets require admin privilege e.g. run from a command run you launched as an admin prompt.
P.S. The cmdlets also support offline operation against a Windows image. You can also un/install packages via DISM.EXE, various other tools or (for the adventurous) use the WinRT API (above) from Powershell v5 via WinRT invocation. In the end it largely boils down to the same thing as these are functional equivalents to the PackageManager API (and in the online cases, are often literally thin wrappers over the API).