WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

Uninstall/Reset/Repair Tasks

Open DrusTheAxe opened this issue 3 years ago • 18 comments

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

DrusTheAxe avatar Jul 25 '22 13:07 DrusTheAxe

[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.

riverar avatar Jul 25 '22 15:07 riverar

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, ...

DrusTheAxe avatar Jul 25 '22 17:07 DrusTheAxe

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?

riverar avatar Jul 25 '22 18:07 riverar

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?

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?

DrusTheAxe avatar Jul 25 '22 18:07 DrusTheAxe

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.

dongle-the-gadget avatar Oct 29 '22 05:10 dongle-the-gadget

https://task.ms/34863092

DrusTheAxe avatar Nov 21 '22 18:11 DrusTheAxe

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?

andy-schmidt avatar Jul 13 '23 21:07 andy-schmidt

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

untoldbyte avatar Aug 14 '23 17:08 untoldbyte

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.

DrusTheAxe avatar Aug 15 '23 07:08 DrusTheAxe

https://task.ms/34863092

cant access

untoldbyte avatar Aug 27 '23 13:08 untoldbyte

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

untoldbyte avatar Aug 27 '23 13:08 untoldbyte

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.

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

untoldbyte avatar Aug 27 '23 13:08 untoldbyte

https://task.ms/34863092

cant access

It's an internal bug tracker.

dongle-the-gadget avatar Aug 27 '23 14:08 dongle-the-gadget

https://task.ms/34863092

cant access

It's an internal bug tracker.

Can we at least get an update

untoldbyte avatar Aug 27 '23 14:08 untoldbyte

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 avatar Apr 23 '24 18:04 stevenbrix

@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?

riverar avatar Apr 23 '24 18:04 riverar

@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 avatar Apr 23 '24 18:04 DrusTheAxe

@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.

riverar avatar Apr 23 '24 19:04 riverar