Some useful things I have learned about Windows Installer and UAC
Recently, I was helping a customer investigate an issue in an MSI-based installer that they created for their Windows Media Center application for Windows Vista. They included a custom action in their MSI that executed RegisterMceApp.exe /allusers to register their application to appear in Windows Media Center. Because they used the /allusers switch, the installer required the ability to access to registry values under HKEY_LOCAL_MACHINE during execution of this custom action. However, their setup failed during the RegisterMceApp.exe custom action with an access denied error.
This led me to undertake a more general investigation into how Windows Installer interacts with UAC. Specifically, I set out to figure out in what circumstances an MSI-based setup will prompt the user for elevation, and how elevated privileges are propagated through the MSI to the custom actions that it contains.
Most of this information exists in MSDN documentation and various blog posts, but I had to put pieces together from several sources to finally form a complete picture in my mind about how things work behind the scenes. I want to use this blog post to summarize the concepts that I learned during my research and try to consolidate some key things in one place for later reference.
In general, Windows Installer will prompt for elevation every time a user installs an MSI unless the MSI author specifically opts out. There are a few key exceptions to this statement:
- If the MSI is run in silent mode (msiexec.exe /qn)
- If the product has already been installed and is managed by Group Policy
- If the user launched setup from a process that is already elevated (such as an elevated cmd prompt)
- If the MSI package already approved for elevation (such as via Group Policy deployment)
- If the AlwaysInstallElevated policy is set on the system
This means that if you author an MSI that contains payload that you know ahead of time will require elevation (such as installing files to Program Files or Windows, writing registry values to HKEY_LOCAL_MACHINE, etc), you do not need to author any special information into an MSI to ensure that it will prompt the user to elevate during installation/repair/uninstallation.
How to author custom actions that require administrative privileges
Many of the issues I have seen related to UAC elevation and MSI-based setups so far have involved custom action that fail due to insufficient privileges. Even if an MSI has been elevated, custom actions must be authored with the correct execution options or the elevated privileges will not be propagated to them and they may fail.
Specifically, a custom action must be authored for deferred execution (using the msidbCustomActionTypeInScript attribute) and must not impersonate the user that launched setup (using the msidbCustomActionTypeNoImpersonate attribute).
In WiX syntax, this means that a custom action must contain the attributes that I have bolded in the following example:
<CustomAction Id="MyCustomAction" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no" />
<CustomAction Id="MyCustomAction" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="commit" Return="check" Impersonate="no" />
Most of the cases I have seen where Windows Media Center application developers have tried to run RegisterMceApp.exe /allusers from a custom action but seen it fail with an access denied error have been caused by not properly setting the msidbCustomActionTypeNoImpersonate bit. In WiX syntax, if you do not specify the Execute attribute, it will default to immediate, which means that the custom action will run with the privileges of the user who ran the setup.
If you are using a Visual Studio 2005 setup/deployment project to create an MSI, there is not a way to set the msidbCustomActionTypeNoImpersonate bit in the designer UI. Instead, you will need to use a custom post-build step like the one I previously described in this blog post to modify the MSI after the build has completed.
I also want to point out that marking a custom action to not impersonate and to run deferred is necessary if the custom action requires elevated privileges in any scenario, regardless of whether or not the MSI is installed on Windows Vista. For example, if you plan to support Group Policy deployment of your MSI on Windows 2000, XP or 2003 with elevated privileges, the custom action needs to be marked with these same flags. This is not a new requirement in Windows Vista.
How to opt out for an MSI that does not require elevation
As a setup developer, it is possible to create an MSI that will not prompt the user for elevation, but it requires some extra steps. You will need to do the following:
- Ensure that no actions performed in your MSI require elevation. This means that all files and registry must be created in a per-user location and no custom actions require administrator privileges
- Set the ALLUSERS property to an empty string
- Set bit 3 of the Word Count summary property to 8 to indicate that elevated privileges are not required
In addition, Windows Vista includes some logic to automatically prompt for elevation for executables that it believes to be setup EXEs. Therefore, if your setup contains a wrapper setup EXE that launches the MSI (as opposed to just an MSI that the user invokes directly), you will need to create and embed a manifest file to prevent Windows Vista from automatically prompting the user for elevation if you have designed a fully per-user setup. You will want to create an application manifest for your setup EXE and and specify the requested execution level of "asInvoker" for your setup process.
For more information, see the section titled Create and Embed an Application Manifest with your Application in the Windows Vista application development requirements for UAC compatibility white paper.
Informing the user of an impending elevation request
Windows Installer 4.0 added a new UI attribute that can be used to add the UAC elevation shield icon to a button in native MSI setup UI. To display this shield, add the ElevationShield attribute to the push button control for the Install Now button in your MSI UI.
Windows Installer will automatically show the shield as part of the button control if it detects that the MSI is running with normal user privileges, and will not show the shield if it detects that the MSI is running with elevated privileges.
A note about logging
In Windows Installer 4.0 on Windows Vista, it is possible to identify what decisions are made regarding UAC elevation during an MSI setup session. To do this, you can search for the prefix MSI_LUA in the Windows Installer verbose log file.
Additional reference information
The following MSDN articles are helpful in understanding how Windows Installer interacts with UAC on Windows Vista:
- Using Windows Installer with UAC - http://msdn.microsoft.com/library/aa372468.aspx
- Guidelines for MSI packages in UAC scenarios - http://msdn.microsoft.com/library/aa368772.aspx
- Installing a package with elevated privileges for a non-administrator - http://msdn.microsoft.com/library/aa369519.aspx
- Authoring MSI packages that will not display a UAC prompt - http://msdn.microsoft.com/library/aa367800.aspx
- Information about the Word Count summary property in an MSI - http://msdn.microsoft.com/library/aa372870.aspx
- Information about custom action in-script execution options - http://msdn.microsoft.com/library/aa368069.aspx
- Using the ElevationShield attribute in MSI UI - http://msdn.microsoft.com/library/aa368344.aspx
Robert Flaming's blog also contains an in-depth series of articles with information about how Windows Installer interacts with UAC. You can take a look at this blog post as a starting point. It contains a table of contents with links to his entire series of posts.
I want to specifically thank Carolyn, the development lead for the Windows Installer, for her patience as I asked several stupid questions to try to better understand these scenarios.
<update date="12/14/2006"> Clarified the comments in the custom action section about execution options. A custom action can be marked as deferred or commit and still allow for elevation to be propagated to it. The key point is that the custom action must include the msidbCustomActionTypeInScript and msidbCustomActionTypeNoImpersonate attributes. </update>
<update date="4/30/2008"> Fixed broken links in the text of this post. </update>