WIX/MSI setup writes to HKLM despite MSIINSTALLPERUSER=1 - wix

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.

Related

Should the installed entry in the registry be in the Microsoft folder?

When adding a shortcut to an installer created with Wix, according to How To: Create a Shortcut on the Start Menu, you need to add a registry value with like this:
<RegistryValue Root="HKCU" Key="Software\Microsoft\MyApplicationName" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
Should that value really be inside of Software\Microsoft? In many cases in the Microsoft world I'm seeing the vendor used as the scope so I'm wondering if it shouldn't really be Software\MyVendorName\MyApplicationName.
I would definitely write to my own location as indicated by others:
HKCU\Software\MyVendorName\MyApplicationName
HKLM\Software\MyVendorName\MyApplicationName
Ideally your application should not write anywhere else in the registry - except beneath these two parent locations. You "own" these two registry locations - and nowhere else. You shouldn't write anywhere else - and certainly not under the Microsoft key. I believe that is a "generic sample".
The exception is when you need to register certain files (or components) - for example COM files whose registration go into HKLM\SOFTWARE\Classes and HKCU\SOFTWARE\Classes. These per machine and per-user locations are merged to produce HKCR (HKEY_CLASSES_ROOT). COM registration can also be isolated, in which case you use manifest files - then the registry is not involved at all. WiX features special COM-related elements that will populate the registry for you via standard MSI mechanisms - the heat.exe tool for harvesting COM registration (among other things) will auto-generate these elements for you and your compiled MSI will have several MSI tables keeping the COM registration information (ProgId, Class, TypeLib, etc...).
UPDATE: Not to compliate things too much, but an MSI can be installed per-user or per-machine based on the values of ALLUSERS and MSIINSTALLPERUSER properties. If you have populated the proper COM tables in the MSI the COM server will be registered per-machine or per-user accordingly.
And there are other cases where installation processes make changes elsewhere in the registry if you install your package. For example when you install drivers, plug-ins, fonts, COM+, COM Interop, file extensions, etc... Your registration in these cases should generally go through APIs that take care of registering your components and you should not poke around i the registry yourself in most cases. A lot of such registration is handled by MSI if you do it right - or built-in constructs in third party tools used to make MSI files.

Create a .config folder in the user folder

When installing my program, I'd like to create a .config folder into the user's folder.
For example :
C:\Users\MyUser\.config
This is what I tried but it doesn't work :
<Directory Id="USERPROFILEFOLDER" Name="[%USERPROFILE]">
<Directory Id="ConfigUserFolder" Name=".config">
<Directory Id="UserConfig" Name="Config" >
<Component Id="ConfigFolder" Guid="GUID">
<RemoveFolder Id='RemoveConfig' Directory='UserConfig' On='uninstall' />
<RemoveFolder Id='RemoveConfigUserFolder' Directory='ConfigUserFolder' On='uninstall' />
<RegistryValue Root='HKCU' Key='Software\MySoftware' Type='string' Value='' KeyPath='yes' />
</Component>
</Directory>
</Directory>
</Directory>
<Property Id="USERPROFILEFOLDER" />
Any idea what I'm missing/doing wrong ?
Is this application a regular executable? Or some sort of Web-App or Plug-In? In other words: does it have its own launch sequence?
I sound like a broken record with this advice, but: folders and files in the user profile folder (and HKCU settings) are better created on application launch than during installation.
Just leave this construct out of your setup and make your application smarter and capable of creating this folder on launch for every user - and to be able to copy any data files into the folder from their template locations in your main read-only %ProgramFiles% installation folder.
I previously wrote a whole rant about the problem of user-specific files and settings deployment: Create folder and file on Current user profile, from Admin Profile. I describe options such as MSI self-repair and Active Setup - and list some details on why they are unreliable (and suggest some potentially better approaches).
I'd say: kill complexity and error sources and stay in familiar territory whenever you can. Avoid advanced setup features due to their hard-to-debug nature and unusual and unfamiliar complexity. And what is relevant for your question: avoid per-user deployment done via the installer.
The above is basically all there is to say, but fleshing it out here are the main reasons to use your application launch sequence instead of your setup for per-user stuff:
Predictability & Reliability: this approach reliably creates the folder for any user who launches your application - without relying on Windows Installer to put per-user files and folders in place.
Windows Installer self-repair can be prevented from running by policy on certain machines (for example terminal servers) and your folder will then never be created at all for users who did not run the original install.
If you also want to install user-specific files (not just a folder), then MSI deployment of user-specified files and settings is unreliable at best, and prone to accidental file and settings overwrite (REINSTALLMODE = amus - force overwrite) and user settings and data loss from unexpected uninstall of settings files intended to be permanent, but not marked as such (by accident). A lot of problems can result from this.
Very technical, but MSI's component GUID concept sort of breaks down conceptually when used to reference count files potentially installed multiple times.
Implementation & Debugging: the application launch sequence is "just regular code" whilst Windows Installer and deployment may be unfamiliar territory for many developers. You hence avoid the unexpected problems that results from the complexity of deployment (a blurb on deployment complexity written in the context of the history of WiX).
This is especially true if you move into custom actions with their complex sequencing, impersonation and conditioning aspects featuring very "conspiratory complexity" (problems that are not immediately obvious, but that will surface when least convenient).
Your application launch sequence has predictable user context, full access to the user's environment and interactivity is available with error- and warning messages. Problems can be debugged easily by simply re-launching the application as opposed to compiling and running a setup (and attaching the debugger in the case of custom actions - well beyond the scope of your question).
You avoid an installer's "one shot" nature and difficulty of debugging due to the hard-to-reproduce nature of deployment errors overall (no access to the problem system, generally missing logging, difficulty of cleaning up prior mistakes). For the launch sequence you just have users re-launch the application and report the error seen - or check the event log or whatever other logging is available.
In my experience QA personnel will generally have more experience testing application launch sequences than deployment features.
And I might be making application debugging sound "too rosy" for what it is in the real world, but trust me it is indeed easier than deployment debugging.
Settings Management: your application's launch sequence can (much more) reliably perform any form of "maintenance" on your data and settings files that is impossible to accomplish reliably from a setup.
These are often "resource files" and not data files - in other words templates and settings used during program operation - not just content created by the user (which sometimes also requires "cleaning" - but you can do that on file open instead of application launch).
You want to fix something in files duplicated for each user
Leaking meta-files pictures
Data file errors and glitches
Just bugs caused by per-user settings really...
Enforce new mandatory settings
Move files to a new location or back them up
Remove settings that are no longer valid (or erroneously unencrypted)
Delete binary streams from HKCU that make your application crash
A description of how a setup can "flag" the system to activate an application's "launch sequence maintenance functions": http://forum.installsite.net/index.php?showtopic=21552 (Feb 2019 converted to WayBack Machine link).
A setup should essentially do anything that requires elevated rights, most other things - do it in your application - and certain elevated things can actually be done over time running as a service - which features no sequencing, conditioning or impersonation variables that plague deployment.
To do this with WiX you need to use the CreateFolder element under the parent component. It's much the same question as this:
how to create folder in Wix?
As a better practice in my opinion, you should use the standard Windows Installer folder properties as locations. The full list is here:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370905(v=vs.85).aspx#system_folder_properties
for example ProgramFiles64Folder, AppDataFolder (which might be the best location for your directory), CommonAppDataFolder and so on.

Wix Toolset RegistrySearch is not saving a registry key

I have an application that is saving multiple registry keys on install to ensure that certain choices a user makes are persisted in the application. Most of these keys work correctly, but some do not record an entry. Am I doing something wrong? or is there a limit on the WiX RegistrySearch? I have checked the documentation and can't find any limit. I have included some examples below :
The following works correctly:
<Property Id="SERVER_NAME">
<RegistrySearch Id='rsSERVER_NAME' Root='HKLM' Key='SOFTWARE\CompanyName\ApplicationName' Name='ServerName' Type='raw' />
</Property>
The following does not work correctly:
<Property Id="SERVER_NAME">
<RegistrySearch Id='rsSERVER_NAME' Root='HKLM' Key='SOFTWARE\CompanyName\ApplicationName\ApplicationDetails\Servers' Name='ServerName' Type='raw' />
</Property>
Is there any reason why the 2nd code block would not work?
If you want to persist property values from user choices it may be easier to just let WiX do it with the "remember property" pattern.
It's not clear how you are saving these values and retrieving them, because there is no indication if you are saving them in 32-bit or 64-bit location, or if you are using the -arch switch to set the default, so it may be that you are saving or restoring them from different bitness locations (see RegistrySearch win64 setting). Without this context it's not clear if that search will work or not. It appears to be a 32-bit search in the absence of Win64=yes, but the -arch switch changes the default.
TEST OK: I ran a test of this and both values were retrieved from the 32-bit section of the registry (HKLM\SOFTWARE\WOW6432Node) without any problems.
Here is the WiX RegistrySearch documentation. And below are the registry paths mentioned by Phil for 64-bit and 32-bit applications - your WiX code specifies 32-bit, so you read from the WOW6432Node section:
HKLM\SOFTWARE (for 64-bit applications)
HKLM\SOFTWARE\WOW6432Node (for 32-bit applications - believe it or not)
I am wondering if you are just mixing up the paths in the registry? Here is where I am reading from - it is in HKLM of course (I cropped the screenshot a bit to make it fit the page):
UPDATE: I have now tested this reading from both the 32-bit and 64-bit sections of the registry. It works as expected as far as I can see? There must be an error in your registry path somewhere?
I use a one-line VBScript to show the property value after the RegistrySearch has run and retrieved the properties. I can update this answer to add this code if you want.
It is a little unclear what you mean when you say that an application is saving multiple registry settings during installation. Is this a custom action you are running which writes these registry keys, and then your setup reads them back?
It is unclear how these values - that you read back from the registry using RegistrySearch - are actually written to the registry? Perhaps they are from a prior version of your application or from another application and you want to "copy" them? If so, can you verify whether they are HKCU or HKLM settings? For HKCU settings I would prefer to do the copy in the application itself for reliability reasons.

How can I conditionally overwrite file during WIX install?

I have two work modes in my installer:
use config files left from previous installation
delete all existing configs and put default configs instead
The mode is determined by the checkbox in the WPF UI of the installer. If second mode is selected, then CustomAction is run, which manually deletes the configs folder from disk:
<InstallExecuteSequence>
<Custom Action="RemoveConfigsFolder" After="RemoveFolders" Overridable="yes">NOT Installed AND DELETESETTINGS=1</Custom>
</InstallExecuteSequence>
I'm using NeverOverwrite attribute:
<ComponentGroup Id="Configs" Directory="INSTALLDIR" >
<Component Id="Configs" Permanent="yes" NeverOverwrite="yes">
<File Id="main.config" Name="main.config" Source=".\Configs\main.config" KeyPath="yes" />
</Component>
</ComponentGroup>
The first mode works fine in this case, but when I try to use second mode it fails and all configs are just deleted and never created again during the installation.
During my research of the issue, I think I've found the reason why this happens: https://community.flexerasoftware.com/showthread.php?96157-The-truth-the-whole-truth-about-quot-Never-overwrite-quot-and-quot-Permanent-quot-files&p=156826#post156826
Actually this is a Windows Installer issue. If you log the uninstall
you will notice that very early in the installation the Installer
decides that the component containing this file will not be installed
because it is marked "Never Overwrite" and a copy of this file already
exists on the target machine. The uninstall happens after that which
removes the existing file. This is because the Installer decides this
when the "CostFinalize" action is launched. This action HAS to be run
before the "RemoveFiles" action.
But how do I fix it?
The problem with settings such as Never Overwrite or Permanent is they look like build settings, but they are not really - they stick to the system attached to the component id. So resetting in the project won't help because it's associated with that id. It's also not clear why setting Never Overwrite might have been a solution to some problem, because by definition patches and overwrite upgrades won't overwrite it, but overwriting it is a requirement of your setup.
Even if you had not set Never Overwrite the Windows Installer rules would not overwrite the file if it was modified after install. So if you had installed it, then it was altered, and then you did an upgrade, the file would not be overwritten (which is another reason why Never Overwrite does not seem needed).
Another issue is that your custom action RemoveConfigsFolder is not marked with an Execute enumeration value, therefore it is immediate, therefore it does not run elevated, therefore it might simply be failing, so without seeing the code it's impossible to say if reports an issue if it can't do the remove. It's also not possible to determine if it explicitly specifies the full path to the folder correctly. So the most likely quick fix to this issue is to mark the custom action as execute deferred, and the DELETESETTINGS value will need to be passed in via CustomActionData.
My initial thought is to remove the 'Never Overwrite' property. Then create a component condition that checks if the file exists. My thought is that your custom action has the condition to correctly remove the config files. If the files do not exist then the components will be selected for install.

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