Wix Installer: Write to HKLM/HKCR in per-user installation without elevated rights - wix

I created a "perMachine" installer with the wix toolset. The installer has to be started with admin rights, because it writes multiple registry keys to HKLM and HKCR.
I'd like to change the installer to a "perUser" installation. Is it possible to do this and still write to HKLM and HKCR? The registry entries have to be there to register a shell icon overlay handler...
Greets
EDIT:
There does not seem to be a way to write to HKLM as non-admin user.
But is there a way to get wix installer to promt for admin pw? If so, I could live with the following solution:
user knows admin pw (or admin provides pw): the icon overlay component is installed
user does not provide admin pw: the icon overlay component is skipped.
So my questions are:
1. How to promt the user for the admin pw?
2. How to skip/install a component based on the users action?
EDIT2:
I have tried multiple combinations of:
InstallPrivileges="elevated"
InstallScope="perUser"
Property "ALLUSERS" set to empty string
Property "MSIUSEREALADMINDETECTION" set to 1
Property "MSIINSTALLPERUSER" set to 1
Condition for said component: "Privileged / AdminUser"
Nothing has worked so far. It all comes down to the Condition not beeing read correctly. I have tried on several PCs with an admin user. In order to get the product to install with ALL features, I have to start the installer explicitly as administrator over the context menu. Otherwise the icon overlay handler won't get installed.

Pointing out something that the OP doesn't seem to understand fully...
Per machine and per user have nothing to do with the privilege required to write to HKLM. Windows Installer won't break security rules either way. If the install requires privilege and doesn't have it, then it fails in both cases. In WiX, the Package InstallPrivileges is what tell Windows whether to elevate so that the install will work. If the installing user doesn't have the privilege the elevation prompt will allow entry of admin credentials. So the answer to your 1 is that InstallPrivileges=elevated should allow entry of an admin account if the user is not admin. otherwise a plain elevation.
You could try a condition on the components containing the restricted registry entries, try a condition of Privileged so they install only if the install is elevated. I have never tried this, but it should work.
https://msdn.microsoft.com/en-us/library/aa370852(v=vs.85).aspx
Other alternatives are:
Group Policy will allow the setup to be pushed to machines of limited users. This is common in corporate environments.
It occurs to me that the shell icon overlay function might be available on a user by user basis. This is a SWAG, and I'm not aware of all the registry entries required, but you can certainly register your COM classes in HKCU, for example. If you use the WiX HKMU key, the items will be created for the machine in a per machine and for the user in a per user. An example here:
http://www.merlinia.com/mdt/WiXTutorial1.msl

No, a per-user install has write-access to only per-user resources like the registry and c:\users when configured for per-user. This has the effect in Vista and later of not requiring elevation and thus not requiring UAC.

Related

Why does MSI installer succeed when chosen component was not installed?

I have an MSI installer package that enforces the user to choose from a list of possible components to install, like "Version 2018" / "Version 2019" / "Version 2020". The chosen components will install themselves in a folder inside "ProgramData" that is usually writeable by every Administrator account on the system. However, in a recent customer support, this folder was created by the SYSTEM account. Probably the customer's IT installed the environment with SYSTEM privileges.
When the installer tries to put files into this folder it obviously fails. The problem is that the installer notices the missing permission, but still succeeds.
Is there any way to enforce MSI installer to abort / throw an error when a user-chosen component (or any other essential component) could not be installed?
What you want should be the default behavior of WiX / MSI as noted below. It's hard to say what's going on without a logfile.
Take a look at the WiX File#Vital attribute: https://wixtoolset.org/documentation/manual/v3/xsd/wix/file.html
If a file is vital, then installation cannot proceed unless the file
is successfully installed. The user will have no option to ignore an
error installing this file. If an error occurs, they can merely retry
to install the file or abort the installation. The default is "yes,"
unless the -sfdvital switch (candle.exe) or SuppressFileDefaultVital
property (.wixproj) is used.
It sets the underlying msidbFileAttributesVital bitmask in the Windows Installer File table as documented at:
https://learn.microsoft.com/en-us/windows/win32/msi/file-table
The file is vital for the accurate operation of the component to which
it belongs. If the installation of a file with the
msidbFileAttributesVital attribute fails, the installation stops and
is rolled back. In this case, the Installer displays a dialog box
without an Ignore button. If this attribute is not set, and the
installation of the file fails, the Installer displays a dialog box
with an Ignore button. In this case, the user can choose to ignore the
failure to install the file and continue.

WIX/MSI setup writes to HKLM despite MSIINSTALLPERUSER=1

I try to create a MSI Single Package using WIX (3.10). The user can select in the UI whether the package should install Per-User or Per-Machine. The package is initialized with ALLUSERS=2 and MSIINSTALLPERUSER=1. I did not set an InstallScope, as this would limit the Package to one or the other.
If the user selects Per-Machine the setup continues with ALLUSERS=2 and MSIINSTALLPERUSER="". - Everything works as expected.
If the user chooses Per-User installation ALLUSERS=2 and MSIINSTALLPERUSER=1 remain unchanged. If a non-privileged user runs the setup everything works as expected as well.
But if a privileged user executes the setup and chooses Per-User installation, registry keys that should be written to HKCU\Software\Classes\ are still written to HKCR / HKLM\Software\Classes\. This happens without UAC being invoked.
I observed this behavior on a Windows 8.1 (current patch level).
This is not what I want. If the user selects Per-User installation, there should be nothing written to HKLM/HKCR.
Here is sample from the wxs-file:
<Component Id="MyRegistryComponent" Guid="{99999999-9999-9999-9999-999999999999}">
<RegistryValue Id="MyRegistryComponent_MainKey" Root="HKCU" Key="Software\Classes\myapp.myclass" Value="myapp.myclass.foo" Type="string" />
</Component>
I checked the MSI with Orca. This RegistryValue has Root=1 in the Registry table of the MSI.
I tried/checked already:
I verified that the ALLUSERS and MSIINSTALLPERUSER properties are
indeed set as stated above.
I tried setting ALLUSERS="" MSIINSTALLPERUSER=1 – No effect.
I changed Root="HKCU" to Root="HKMU" in the wxs.
This results in Root=-1 in the MSI, but I does not change the final
result after installation.
What am I missing here?
Is possible that this behavior is caused by previous incomplete (un-)installations?
When you say "This results in Root=-1 in the MSI, but I does not change the final result after installation." it's not clear which of the results you're referring to but:
HKCU will always go to HKCU, HKMU is what you need to switch between HKCU and HKLM in a single package setup. So using HKMU and producing a verbose log would be useful to see if there is a failure somewhere in there.
You will get changes in HKCR. That's usually the normal behavior because as this article explains:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
Quote "The HKEY_LOCAL_MACHINE\Software\Classes key contains default settings that can apply to all users on the local computer. The HKEY_CURRENT_USER\Software\Classes key contains settings that apply only to the interactive user. The HKEY_CLASSES_ROOT key provides a view of the registry that merges the information from these two sources. HKEY_CLASSES_ROOT also provides this merged view for applications designed for previous versions of Windows."
HKCR is a virtual view that combines class registration for the current user with class registration for the machine to present a view of all class entries on the system. Other accounts (such as the system account) will see only HKLM, so what you see exactly depends on who you are.
I suggest that is what is needed here is a test case that uses HKMU as is required, and maybe post that test case. Keep in mind that seeing HKCR entries is normal, going by the documentation, so maybe that explains all that you are seeing.

Write to local machine registry in custom action (conditionally)

Windows Installer has the smart feature to automatically decide whether to store registry values under HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE (using Root="HKMU" in WiX).
I need to write some complex registry keys during installation so I created a custom action for this. Depending on whether ALLUSERS is set or not HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE will be the location that is used by the custom action.
Unfortunately, I had to realize that even in an ALLUSERS installation the custom action does not have the required privilege to write to HKEY_LOCAL_MACHINE unless the installation is started as administrator. How do I get the custom action to write to HKEY_LOCAL_MACHINE but still keep the option of a per-user install?
Don't use a custom action, you'll lose all the other smart features of Windows Installer such as ugprades, rollbacks, uninstalls and so on.
Instead, put the registry values in their own component and put a condition on the component. If the condition evaluates to true the component and it's associated registry resources will get installed.
Take a look at the Privileged property. It sounds like what you are looking for to do your evaluation.

Per-user MSI non-elevated by default - how to show an elevation prompt for writing to a folder?

I have an MSI built via WiX, it's per-user and doesn't display the UAC prompt if the user has rights to the destination folder. However, if the destination folder is in Program Files, it errors with "Insuficient privileges".
How can I show a UAC prompt in the case the destination folder is not writable?
It doesn't really work that way. Per User installs should never require elevation and should never write to Program Files as that's a per machine location. Instead it should install to %LocalAppData%\Programs\Company\Product.
Read the following for a lot more background information. Parts apply and parts may be beyond scope ( dual per-user / per-machine requirements ):
Authoring a single package for Per-User or Per-Machine Installation context in Windows 7
I know this is an old thread, but I want to let others who come across it that it is indeed possible.
As was mentioned in the previous answer, conventional per-user installs should not require admin rights. However, I came across a perfectly valid situation where I needed to run a custom action which required admin rights. Requiring my users to launch the MSI with msiexec from a command line with elevated privileges did not seem like an acceptable solution.
It doesn't seem like this should be so difficult, but luckily I stumbled onto the answer in this post: The Package/#InstallScope attribute doesn’t support per-user, elevated packages! So just omit it in your Package definition:
<!-- NOTE: If you need to create a per-user installation (meaning it's not -->
<!-- visible in Add/Remove Programs from other logons) that prompts for -->
<!-- elevation, omit both the Package/#InstallPrivileges="elevated" and
<!-- Package/#InstallScope="perUser". -->
<Package InstallerVersion="200" Compressed="yes" />
Don't forget to leave ALLUSERS undefined, as well. I described this further on my blog:
How to Elevate a Per User Installer Using WiX

What is the best way to specify whether InstallPrivileges is limited or elevated at the command line in WIX?

I want to create an MSI in WiX such that it can take a command line parameter to indicate whether it is a per-machine or per-user installation and consequently whether to raise a UAC dialog.
What is the best way to accomplish this?
This is the link for per-machine/per-user from MSDN.
so to change the values from the command line parameter, you'll need something like so:
msiexec /i myinstaller.msi ALLUSERS=[1|2]
Also, have a look at this link from wix-users
The UAC dialog is controlled by a bit in the SummaryInformation stream. That, unfortunately, means it cannot be controlled at "run time" (install/repair/uninstall). You have to build different MSI files to truly change the UAC prompt.
I haven't been able to test in Vista yet, but what works in XP for limited user per user install and admin user per machine install is the following:
msiexec /i myinstaller.msi ALLUSERS="" INSTALLDIR="C:\Documents and Settings[Username]\Local Settings\Application Data\My COmpany\My Program"
The INSTALLDIR can be anything that a limited user can write to. The above is the directory Google Chrome uses. Found from the following link that the ALLUSERS property can actually be blank which is distint from 1 or 2 and that correctly sets the ProgramDir and Desktop locations
http://blogs.msdn.com/astebner/archive/2007/11/18/6385121.aspx