WindowsAppSDK
WindowsAppSDK copied to clipboard
Uninstall/Reset/Repair Tasks
Proposal: Uninstall/Reset/Repair Tasks
Summary
Provide an uninstall hook for custom activity equivalent to windows.preinstallConfigTask and windows.updateTask. Also potentially provide similar support for 'repair' and 'reset' operations.
Microsoft-internal task 34863092
Rationale
Packaged apps have the opportunity to have code run when a package is installed or updated via the
windows.preinstallConfigTask or windows.updateTask but have no equivalent option when a package
is uninstalled.
Applications can write data outside locations known by and managed by the Deployment stack (e.g. locations under HKLM). Processes running in an AppContainer have constrained access to the system so data is readily handled by Windows when a package is deregistered but MediumIL and elevated processes can (and often do) write outside these managed locations. As a package can be removed without the package's direct involvement a mechanism is needed to enable these apps to remove data written to places or ways unknown to the Deployment stack.
'Reset' needs similar support. A 'reset' operation is functionally equivalent to
packageManager.RemovePackageAsync(p, RemovalOptions.PreserveApplicationData) but the package
package directory is not deleted followed by packageManager.AddPackageAsync(p). As this is
similar to but not exactly 'uninstall + install' the work performed by an uninstall task
may be inappropriate. Although an uninstall task could have a parameter indicating
Reason=<Remove|Reset> a separate specific task is simpler and more developer friendly.
In addition, the currently install/update task model is a separate task and
appxmanifest.xml schema.
A 'repair' operation is functionally equivalent to packageManager.RegisterPackageAsync(p) for a
package already registered to a user. However, register operations also occur for a loose file
package so there's no clear task to invoke for 'repair' scenarios. A windows.repairTask solves
this ambiguity.
Uninstall tasks must occur after a deregisteration operation is requested but before any deregistration work can be performed. Thus, uninstall tasks are blocking operations. Similarly, repair tasks are blocking operations. These should be time bound to prevent unconstrained delays e.g. an uninstall task running for an hour would be a poor user experience.
Reset tasks are non-blocking to the Deployment pipeline. This occurs after Deployment work is
completed like a windows.updateTask. The latter have no time constraints imposed by Deployment
so reset tasks shouldn't need any Deployment imposed time constraints.
Scope
| Capability | Priority |
|---|---|
Support a windows.uninstallTask invoked when a package is deregistered for a user |
Must |
Support a windows.repairTask invoked when a package is repaired for a user |
Must |
Support a windows.resetTask invoked when a package is reset for a user |
Must |
Time bound windows.uninstallTask execution |
Should |
Time bound windows.resetTask execution |
Should |
Important Notes
Links to related discussions:
- #16
- #2322
Open Questions
N/A
[from rationale] As a package can be removed without the package's direct involvement a mechanism is needed to enable these apps to remove data written to places or ways unknown to the Deployment stack.
MSIX guarantees a clean uninstall, so what data are you referring to here? Sounds like if there's untracked data as suggested, this is a MSIX bug.
I'm very concerned this is being requested for a partner to pop open a web browser for some tracking, analytics, exit survey, and/or other generally unwanted behavior.
MSIX guarantees a clean uninstall, so what data are you referring to here?
Packaged apps can run MediumIL and elevation which can (and do) color outside the lines. For example, some unpackaged apps have extensibility or integration models requiring regkeys or files be written in places not managed by the Deployment stack. Apps running at >=MediumIL can write to these locations, but have no reliable mechanism to remove that data when their package is removed.
Sounds like if there's untracked data as suggested, this is a MSIX bug.
There's a lot of data across Windows (the OS and ecosystem) which isn't managed by MSIX that some apps need to modify. Some of these are impossible for MSIX to properly manage without breaking impact to these unpackaged apps so either there's zero unpackaged apps (only packaged) or we need a way to support these older mechanisms. The former doesn't seem likely anytime soon 😋 so this is a necessity for healthy systems.
I'm very concerned this is being requested for a partner to pop open a web browser for some tracking, analytics, exit survey, and/or other generally unwanted behavior.
Can a BackgroundTask pop open a web browser to engage in these activities today? That's what windows.preinstallConfigTask and windows.updateTask work today, they activate a manifested background task. Can a background task be defined imperatively (no manifest) and pop open a web browser?...
These uninstall/repair/reset tasks wouldn't enable these actions any more than possible today.
Also, this has been requested by other teams before (via other channels). The need/priority hasn't risen 'above the line' to act on it so far, but times and needs can change... This enhancement request is vFuture/backlog, noted to gather feedback and consideration in planning cycles yadda yadda all the usual reasons. Feedback is welcome - on all facets: functionality, restrictions, need, ...
The existing windows.preinstallConfigTask and windows.updateTask tasks seem to be targeting OEMs/MOs (akin to a rescap). Do you know if that's enforced? If so, should this task also have the same restrictions?
The existing
windows.preinstallConfigTaskandwindows.updateTasktasks seem to be targeting OEMs/MOs (akin to a rescap). Do you know if that's enforced?
windows.preinstallConfigTask is restricted to provisioned (and inbox) packages. OEMs often provision packages but so do others (eg enterprises). Anyone can declare it, but it's only acted on if the package is provisioned (or inbox).
Anyone can provision a package via PackageManager.ProvisionPackageForAllUsersAsync(), the Powershell cmdlet Add-AppxProvisionedPackage or dism.exe if they have admin privilege. At that point you p3wn the machine anyway so there's no added threat.
windows.updateTask has no such constraint. Any package can declare it and it'll be invoked when a user's registered packaged is updated. No provisioning required, not any capability as I recall.
If so, should this task also have the same restrictions?
What do you think?
I think that there should also be an option for the uninstall action to run as administrator. Either by having something like RunAsAdmin="true" or allowing the uninstall app to elevate itself on launch.
As for the restrictions, I feel like runFullTrust (and allowElevation for the 'run uninstaller as admin' scenario) should be enough.
https://task.ms/34863092
This looks awesome, we really could use this functionality. This is a definite improvement over using the customInstallActions restricted capability. See also https://github.com/MicrosoftDocs/winrt-related/issues/194
What is the status on development of this feature?
There is another important use case
Lets say that an msix app regsiters a font to the OS, now msix uninstall will failas the font maybe in use and hence locked
it is possibleto placethe font outside of sandbox and uninstall will succeed but this will keep the fonts registered with no means to unregister
this and similar use cases need custom hooks
Lets say that an msix app regsiters a font to the OS
Registers how? Sorry, I'm only lightly savvy about font registration. Is this a manifested registration like `<Extension Category="windows.sharedfont"> or via some Windows API to register a file in the package?
If the latter and the font is loaded and cannot be deleted it shouldn't fail the uninstall -- removing the package should not fail. This usually appears as an ERROR_SHARING_VIOLATION or E_ACCESSDENIED (depending) but remove is, by definition, a best-effort operation. Deployment should not fail an uninstall for such things but rather log the error and move on. Worst case the deployment operation succeeds but the package directory (or something under your ApplicationData directory) remains. In this event the unable-to-be-deleted files/dirs are tracked and 'cleanup' is periodically retried, including worst case after the next reboot.
Partially uninstalling a package won't fail the RemovePackage operation, but having that partial package directory/content hanging around can block a 'new' install of the package (well, it'll seem new since you uninstalled the the package and there's no record of it being present anymore).
But regardless, yes, this is an example where an app can register resources with Windows which the MSIX deployment stack has no knowledge of, and thus no ability to help clean up on uninstall (or update, reset or repair scenarios). ApplicationData.Local[Cache]Folder can be a viable option in some cases (copy files to LocalCacheFolder and register there), but only some. Hooks like the uninstall/reset/repair tasks proposed here provide a means to handle those more offbeat scenarios the deployment stack can't.
Manifested features like windows.sharedFonts are another matter entirely. They're designed to be savvy to this issue and shouldn't be a problem. If they are it's a bug and one we'd be very interested to hear about. Please let us know if you find such a thing.
https://task.ms/34863092
cant access
the inability to run custom uninstall hook means that my app cant do something simple as creating a user read protected directory to prevent access to proprietary stuff like mov, fonts.
if the folder is set these permissions
the msix uninstall leaves behind the package folder and then it cannot be installed again!
this is a critical issue
Lets say that an msix app regsiters a font to the OS
Registers how? Sorry, I'm only lightly savvy about font registration. Is this a manifested registration like `<Extension Category="windows.sharedfont"> or via some Windows API to register a file in the package?
If the latter and the font is loaded and cannot be deleted it shouldn't fail the uninstall -- removing the package should not fail. This usually appears as an
ERROR_SHARING_VIOLATIONorE_ACCESSDENIED(depending) but remove is, by definition, a best-effort operation. Deployment should not fail an uninstall for such things but rather log the error and move on. Worst case the deployment operation succeeds but the package directory (or something under your ApplicationData directory) remains. In this event the unable-to-be-deleted files/dirs are tracked and 'cleanup' is periodically retried, including worst case after the next reboot.Partially uninstalling a package won't fail the RemovePackage operation, but having that partial package directory/content hanging around can block a 'new' install of the package (well, it'll seem new since you uninstalled the the package and there's no record of it being present anymore).
But regardless, yes, this is an example where an app can register resources with Windows which the MSIX deployment stack has no knowledge of, and thus no ability to help clean up on uninstall (or update, reset or repair scenarios).
ApplicationData.Local[Cache]Foldercan be a viable option in some cases (copy files to LocalCacheFolder and register there), but only some. Hooks like the uninstall/reset/repair tasks proposed here provide a means to handle those more offbeat scenarios the deployment stack can't.Manifested features like windows.sharedFonts are another matter entirely. They're designed to be savvy to this issue and shouldn't be a problem. If they are it's a bug and one we'd be very interested to hear about. Please let us know if you find such a thing.
we need to make a directory read protected by applying special permissions using ACL or similar. I have tried and the uninstall leaves behind the whole package folder i.e. appname+hash inside packages.
will this get auto deleted on reboot m sure not cause the permissions are still there.
any guidance on how we can achieve this would be great.
also no matter what, lets say if we need to unregister the device for tracking purpose or unregister custom assets like fonts this simply cant be done without a custom hook
its a necessity especially since MAUI based apps need msix to be used
https://task.ms/34863092
cant access
It's an internal bug tracker.
https://task.ms/34863092
cant access
It's an internal bug tracker.
Can we at least get an update
I'm very concerned this is being requested for a partner to pop open a web browser for some tracking, analytics, exit survey, and/or other generally unwanted behavior.
i'm not sure why an exit survey would be considered unwanted? i think it would be useful to know why people are uninstalling the app
@stevenbrix Privacy: The survey could fingerprint the machine, browser usage, identify the user, IP address, etc. General UX: What if the user is updating their browser? What if the browser is blocked and generates a weird policy error? What if the user doesn't have internet access?
@stevenbrix Privacy: The survey could fingerprint the machine, browser usage, identify the user, IP address, etc. General UX: What if the user is updating their browser? What if the browser is blocked and generates a weird policy error? What if the user doesn't have internet access?
MediumIL apps can already do much of this. This specific feature is support for a backgroundtask to be run on uninstall, just like on (pre)install and update. I'm not seeing how an uninstalllTask creates new threats. Aren't your privacy concerns aren't a factor for (pre)install and update?
@DrusTheAxe Agreed. I was just addressing Steven's general question about how exit surveys could be considered unwanted.
In this case, updateTask appears to be unrestricted so the cat is already out of the bag. Completing the toolbox with uninstall, reset, repair, seems to make sense.