Ignoring disallowed property IISMAJORVERSION and 'EnableUserControl'? - wix

My installer package works on my machine but failed on my colleague's machine. Looking at the log, I can see a few properties values are not persisted during ExecuteAction phrase: there are few Ignoring disallowed property lines in his installer log file and those properties are set with the right value during UISequence. The strange thing is that we are both Admin user on local machines he is and Domain Admin as well while I am not, and we are both on Windows 7 64bit. So I don't think it is because he don't have Administrator rights.
The exact entries in the log file:
MSI (s) (3C:50) [09:14:16:583]: Ignoring disallowed property IISMAJORVERSION
MSI (s) (3C:50) [09:14:16:583]: Ignoring disallowed property IISMINORVERSION
MSI (s) (3C:50) [09:14:16:583]: Ignoring disallowed property WCF_SRV_INSTALL_FOLDER
MSI (s) (3C:50) [09:14:16:583]: Ignoring disallowed property TARGETDIR
A easy fix would be mark all those properties as Secure, but properties such as IISMAJORVERSION are not defined in my code. I discovered that I can set EnableUserControl to 1 to make Ignoring disallowed property go away. Another solution would be create my own security properties and copy whatever ignored property value I need into my own properties and read them instead of the ignored property.
After that I discovered there is an entry Machine policy value 'EnableUserControl' is 0 in his installer log, but not in my log, which seems point to set EnableUserControl to 1 is probably what I need. In that case, the question is why there are different values from those two machines?
So my number one question would be: is set EnableUserControl a good fix for my solution, or there are probably better/safer solutions given I only seems found the symptoms but not the cause?
Or if EnableUserControl seems like a reasonable fix given the information, any suggestion could help me track down the cause of the problem (a registry key value change by the Administrator, probably?).
I don't think there is anything special about my installer, but in case of anyone want to see more details:
<Package Id="*" InstallerVersion="200" Description="Web service installer" Compressed="yes" InstallScope="perMachine" />
Edit:
As pointed out by PhilDW, those properties probably should be marked as Secure to begin with. But then shouldn't all properties be marked as Secure because of UAC, I don't think is make much sense to define a property to be not Secure if it might be used by others?

I'm pretty sure it doesn't matter if you defined them or not - try marking them Secure.

Related

How to achieve authoring a single package for per-user or per-machine installation

I tried all the scenarios for creating a single MSI for per-user and per-machine. Below is my explanation: According to https://blogs.msdn.microsoft.com/windows_installer_team/2009/09/02/authoring-a-single-package-for-per-user-or-per-machine-installation-context-in-windows-7/
<Property Id='ALLUSERS' Value='2' />
<Property Id='MSIINSTALLPERUSER' Value='{}' />
Results in a per-machine installation and the value of MSIINSTALLPERUSER is "1" results in per-user installation.
Now I am running a custom action which determines the user is whether admin or not and so changing the property value to be {} or 1.
My problem is the value of "ALLUSER" is changed to 1 Before logging during installation. The log created shows:
"PROPERTY CHANGE: Modifying ALLUSERS property. Its current value is '2'. Its new value: '1'."
But When i run by directly giving MSIPERUSER Value as "1" The log shows:
"PROPERTY CHANGE: Deleting ALLUSERS property. Its current value is '2'."
So please help me how can i develop a single installer for both admin user and normal user.
Thanks in advance.
Basically you follow the rules here:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd408068(v=vs.85).aspx
The point here is that Windows decides how the install works based on the user's privileges, not you with a custom action. That's why the property values change. Follow those rules and it just works.

Wix Bundle Upgrade Without Resupplying Password

I have authored an MSI that requires an account and password to be supplied to install and start a Windows Service, so I've added a couple of properties to my 'Product' element for that. I have a requirement that these properties should not need to be resupplied to perform an upgrade and since one of those properties is a password I don't want to persist it's value to the registry (or anywhere). I have achieved this with
<MajorUpgrade ... Schedule="afterInstallExecute" />
Now I'm authoring an exe bootstrapper to bundle this MSI with it's prerequisite, similarly the exe will need to receive values for the properties and pass them to the MSI, so I've added some 'Variable' elements to my bundle and passed them to my 'MsiPackage' element with child 'MsiProperty' elements. And this works great during first install when the values are supplied, but now when I want to upgrade the bundle without supplying values for the properties the bootstrapper passes empty values to the MSI. Something equivalent to...
msiexec /i MyMsi.msi ACCOUNT= PASSWORD=
Which breaks the upgrade. The new version of the Windows Service is attempting to start with an empty value for account and password.
Is there a way to conditionally pass variable values to MSI's as property values?
What happens when both the 'Variable' element attributes 'Hidden' and 'Persisted' are set? Will the password really be hidden?
Is there another pattern I don't know about / haven't thought of?
Something like this doesn't feel like it should require a custom action.
On upgrades you can disable the <InstallServices> standard action.
In one of the products I work with I have the following:
<!-- http://stackoverflow.com/questions/15965539/how-to-only-stop-and-not-uninstall-windows-services-when-major-upgrade-in-wix don't change service config on upgrade -->
<DeleteServices>NOT UPGRADINGPRODUCTCODE</DeleteServices>
<InstallServices>NOT WIX_UPGRADE_DETECTED OR V6INSTALLED</InstallServices>
Because I didn't want to reset the start types of the services is the user has decided to start them manually instead of automatically (it's an option in our product to set this).
By doing this, it should leave the service already installed as is when upgrading instead of trying to re-add it with empty parmeters for the login user/pass
An alternative is to make a salted hash of the password and store the user and salted&hashed password into the registry. On upgrades you can read these values decode the password and use those values.

Prevent custom actions from running during patch

I am authoring a very small patch to a very large package, it's sole purpose is to update a single file and add four smaller ones.
Using the WiX help as a guide I am able to generate the MSP file.
However, a patch runs apparently it runs the original package in reinstall mode, with all the custom actions and whatnot that go along with it, which is not what I want.
Further research turned up the OptimizeCA property of the MsiPatchMetadata table, and its WiX equivalent OptimizeCustomActions which allows custom actions to be skipped when applying a patch.
That sounded exactly what I wanted but unfortunately it did not work as expected. The original package has a bunch of XML config file change custom actions, and looking at the log it appears to be erroring out when it hits the XmlFile CAs:
MSI (s) (58!74) [14:53:24:928]: PROPERTY CHANGE: Adding ExecXmlFileRollback property. Its value is (stuff deleted)
MSI (s) (58:74) [14:53:24:928]: Doing action: ExecXmlFileRollback
Action 14:53:24: ExecXmlFileRollback.
Action start 14:53:24: ExecXmlFileRollback.
MSI (s) (58:74) [14:53:24:928]: Skipping Action: ExecXmlFileRollback. It is being skipped as per the value provided for OptimizeCA in MsiPatchMetadata table of an applicable patch
Action ended 14:53:24: ExecXmlFileRollback. Return value 0.
SchedXmlFile: Error 0x8007065a: Failed MsiDoAction on deferred action
SchedXmlFile: Error 0x8007065a: failed to schedule ExecXmlFileRollback for file: (file)
SchedXmlFile: Error 0x8007065a: failed to begin file change for file: (file)
Action ended 14:53:24: SchedXmlFile. Return value 3.
You can see that the OptimizeCA property is being respected for the ExecXmlFileRollback action, as it is being skipped, but something goes wrong when it tries to schedule it and that causes the whole thing to crash the installer.
This is the relevant part of my WiX patch authoring:
<OptimizeCustomActions
SkipAssignment="no"
SkipImmediate="no"
SkipDeferred="yes">
</OptimizeCustomActions>
I'm really having a hard time figuring out what to try next. I found another person having the exact same issue as me on wix-users but there was no response to the query.
A condition including "Not PATCH" should prevent the CA from running during patch install.
Alternatively, "Not Installed" would prevent it from running if the product is already installed, because it looks like you'd have a similar issue during a repair.

SetARPINSTALLLOCATION wrong value

<Custom Action="SetARPINSTALLLOCATION" After="InstallValidate">NOT (REMOVE="ALL" or REMOVE="ProgramFiles")</Custom>
I have this custom action called in InstallSequence, action that must populate in upgrade INSTALLDIR from registry, and this custom action is called in fresh install also.
In majority of cases this action, for fresh install, return one location from local machine, and the setup works without issues, but on a customer machine the value returned is \SomeDir\ and the setup faills.
How could I use this custom action to work correctly?
After some analysis I found that the functions works correctly, but the system contained an invalid registry entry, and for that value the result of SetARPINSTALLLOCATION was a wrong value.
The wrong value in registry was generated by the existence of record InstallLocation directly on uninstall registry key, without any guid like parent.
Thanks.

Wix installer (3.0) - how do I write to the Registry after success or fail of the installation?

I have an application that will be installed by another program (basically a wrapper that installs multiple applications and reports pass/fail for each). The requirement from the wrapper development team is that my application must write either Success or Fail to a specific registry key after the installation completes.
For my solution, I was thinking I could initilize the registry key to Success when the installtion begins, and update the value to Fail only if the installation fails (or the other way around).
Based on reading examples, browsing through the Wix Help, and searching for similar issues, I'm pretty certain I need to use a Custom Action, something like
<Custom Action="SetInstallationStatusFail" After="InstallFinalize">NOT Installed</Custom>
The place I'm stuck at now is that I don't know what code I need to write for the SetInstallationStatusFail in order to update the registry key. I'm also not sure what Parent element to stck it under. I think it should be something simple like this
<RegistryValue Action="write" Root="HKLM" Key="SOFTWARE\$(var.RegistryCompanyName)\$(var.RegistryProductName)\InstallStatus" Name="install" Type="string" Value="Fail" />
If you think I'm trying to do something that isn't valid, or if you know of a better solution for wrting to the registry after install, please let me know. Thank you.
It's a bad requirement because the registry value would be "orphaned" with nothing to clean it up. MSI already provides a way to determine success or failure: the return code. See "Error Codes" in the MSI SDK for a list.
MSI doesn't provide a way to write to the HKLM registry after failure, either natively or via custom action. (There are actions that can be triggered on error but they don't have privileges to write to HKLM.)
Have a chat to the wrapper guys and see if they are willing to consider other options - even if they can't accept return codes and want to check somewhere else there are still other ways to do this using the Windows Installer API.
For example, here's a really simple VBScript to loop through the currently installed products looking to see if an application is installed by name.
productName = "My Application"
Set installer = Wscript.CreateObject("WindowsInstaller.Installer")
For Each productCode In installer.Products
If LCase(installer.ProductInfo(productCode, "ProductName")) = LCase(productName) Then Exit For
Next
If IsEmpty(productCode) Then
Wscript.Echo "Couldn't find " & productName
Else
Wscript.Echo "Found " & productName
End If
Another option would be to test if the value in the registry exists.
Your installer writes a value to the registry, the value can be Success. If the value exists in the registry, then installation was successful; if it does not, then installation failed.
Here is a thought. You can write registry value in both cases in the success case or failure case. Write a custom action to write success value. Write and schedule a rollback custom action to write failed value. If install fails it will be rolled back and the rollback custom action will write failed. If it succeeds you write value success in the custom action with condition not installed.
In either case These registry values can be deleted during uninstall. This may not be an elegant solution but if this is your requirement then you can fulfill it.
Perhaps Bob Arnson can comment upon this solution.