WIX condition only on Install not working - wix

I have the following within the Product Tag:
<Property Id="LICENSEKEY" Admin="yes" Hidden="no">
<RegistrySearch Id="RememberLicenseKey" Root="HKLM" Key="SOFTWARE\MyApp\key1\Settings" Name="LICENSEKEY" Type="raw"></RegistrySearch>
</Property>
<Condition Message="License key is required to proceed">LICENSEKEY AND NOT Installed</Condition>
What I want to do is pass the License key as a command line argument to msiexec, and then set it in the registry. If the key is not passed I want to cancel the installation. Therefore, this check only needs to be run at install time. However, the condition that I have added causes a popup both at install and uninstall time. Can't seem to figure out what I am doing wrong.
EDIT:
I tested with the following condition and it seems to show the message both on install and uninstall:
<Condition Message="License key is required to proceed">NOT Installed</Condition>

The Message for a Condition element will be displayed when the condition evaluates to false, meaning the condition was not met.
This is noted in the Message attribute description in the WiX Condition documentation:
Set the value to the text to display when the condition fails and the installation must be terminated.
To resolve this issue, the logical operators in the Condition just need to be changed to LICENSEKEY OR Installed
This is a late answer, but, hopefully, this will help any future visitors that find this question.

You may need to clarify your requirement. That WiX source does a search for the key, so does it need to be passed on command line or you'll cancel the install (as your post says), or can it be used if it's found in the registry by that registry search? Currently it appears that your registry search is overwriting anything you pass on the command line, including setting it to null, so check that with a verbose log.
Also, all the launch condition examples I've seen or used have a CDATA around the text of the actual condition - that may be part of the problem.
I'll assume you allow the key on the command line or in the registry. So your registry search should be for another property name, let's call it REGKEY, so it doesn't set your passed LICENSEKEY to null. Then you have a set property (type 51) custom action immediately after the search that sets LICENSEKEY to REGKEY with a condition of -Not LICENSEKEY- so it will set LICENSEKEY to REGKEY only if LICENSEKEY was not passed on the command line. So if you pass it on the command line it will be used, otherwise the registry one will be used. At that point, a condition of LICENSEKEY should work ok as a launch condition. Internally, the AppSearch that finds the registry item is typically immediately followed by the launch condition check in a WiX MSI, so you need to set LICENSEKEY before the launch condition check.

Related

How to test if a parameter is passed into msi command line?

I am trying to install a msi file using msiexec on Windows. This msi can be installed either into the default ProgramFiles dir or a custom dir specified in the msiexec command.
For example when the custom dir is specified, the command looks like this:
msiexec /i installer_name.msi CUSTOM_DIR="C:\TEST" ALLUSERS=1
When CUSTOM_DIR is not specified then the command is
msiexec /i installer_name.msi ALLUSERS=1
For this to work, I am changing a Wix file and creating Custom Action and Custom Action Id.
When CUSTOM_DIR is passed by the installer, then
<Custom Action='InstallAppCustom' Before='InstallFinalize'>VersionNT64 and (CUSTOM_DIR) and (ALLUSERS=1)</Custom>
and when the CUSTOM_DIR is not passed then
<Custom Action='InstallApp' Before='InstallFinalize'>VersionNT64 and (Not CUSTOM_DIR) and (ALLUSERS=1)</Custom>
My questions are:
Is this the right way to check whether CUSTOM_DIR is passed or not? or any other right way to check it?
The issue here is that, irrespective of whether CUSTOM_DIR is passed or not, InstallAppCustom gets executed in the InstallExecuteSequence.
InstallAppCustom is getting executed everytime because CUSTOM_DIR will be always set. It must have initialized to some default value using Directory table. So, even if you didn't pass parameter, CUSTOM_DIR value will be set.
I understand why you want to check if parameter is passed from command-line but what if user changes CUSTOM_DIR value from UI? If it's not exposed to UI, then it's fine.
So, to check whether a property is passed from command-line, you need set property custom action which should be scheduled as very first action of InstallExecuteSequence, UISequence. Set property action will set CMD_CUSTOM_DIR property and its value would be [CUSTOM_DIR]. This should have condition of CUSTOM_DIR as at this point of installation time, default value of CUSTOM_DIR is not set. So, CMD_CUSTOM_DIR will always have cmdline value if passed and same can be used later on in other custom action conditions.
You can check the log msiexec /i yourmsi /l*v setup.log. There all cmd parameters and property changes and values are shown.
The above answer by Vivek helped me to solve the issue I had.
So I implemented something like:
<Property Id="DllPath32" Value="[ProgramFilesFolder]\App Name\dependencies"/>
<Property Id="DllPath64" Value="[ProgramFiles64Folder]\App Name\dependencies"/>
<!--CustomAction Id='SetDllPath64' Property='DllPath64' Value='[ProgramFiles64Folder]\\App Name' Return='check' /-->
<!--CustomAction Id='SetDllPath32' Property='DllPath32' Value='[ProgramFilesFolder]\\App Name' Return='check' /-->
<!--Custom Action='SetDllPath64' After='AppSearch'>VersionNT64</Custom-->
<!--Custom Action='SetDllPath32' After='AppSearch'>Not VersionNT64</Custom-->
The installation of the app worked as expected. Only issue is that, while uninstalling the app, the ProgramFiles64Folder is not changing to C:\Program Files.

WIX MSI conditions

In the Zabbix Agent MSI, there is the following line, when one opens MSI:
<Condition Message="Please enter the name or IP address in the Zabbix server IP/DNS field !">NOT (NOT (Installed OR WIX_UPGRADE_DETECTED OR WIX_DOWNGRADE_DETECTED)) OR ((NOT (Installed OR WIX_UPGRADE_DETECTED OR WIX_DOWNGRADE_DETECTED)) AND ((UILevel<5 AND SERVER) OR UILevel=5))</Condition>
Can someone explain the logic? When one rewrites the condition in a more sensible way:
NOT (
NOT (Installed OR WIX_UPGRADE_DETECTED OR WIX_DOWNGRADE_DETECTED)
) OR (
(NOT (Installed OR WIX_UPGRADE_DETECTED OR WIX_DOWNGRADE_DETECTED))
AND ((UILevel<5 AND SERVER) OR UILevel=5)
)
So if Installed=1 then the condition is satisfied due to the double NOT (which it should not be, since the message should only appear if the software is not installed and thus, there is an error in the MSI). The double NOT makes no sense.
Or is there some other interpretation of the condition above?
This is all governed by Windows Installer's Conditional Statement Syntax
https://learn.microsoft.com/en-us/windows/win32/msi/conditional-statement-syntax
It appears your trying to do custom UI work but I don't know how all of that relates to a server name IP address.
In these scenarios I have a custom action that implements business rule checks (reach out and touch a server or validate FQDN/IP ) and set a property to 1 or 0. Then I use mutually exclusive control events (Publish elements with Condition in the inner text ) to either Spawn a dialog that says there is a problem or NewDialog the next dialog of the wizard loop.

wix unable to use string in detect condition

I am using WIX installer to genrate exe, till now everything is working fine but now i need to add one detect condition in exe package as given below.
<ExePackage
Id="AccessRuntime2013"
DetectCondition="((MsAccessInstalled = Outlook.Application.15) AND (MSOffice2013RuntimeInstalled = 0))" >
MsAccessInstalled is a variable which stores version of outlook installed and MSOffice2013RuntimeInstalled is a variable which checks whether access runtime is installed or not. Both variables are setting properly.
I have to run this exe only when MsAccessInstalled = "Outlook.Application.15" and MSOffice2013RuntimeInstalled is not installed. If i run both condition separate then it works but if i clubbed both it doesn't works. It gives error message as Failed to parse condition "((MsAccessInstalled = Outlook.Application.15) AND (MSOffice2013RuntimeInstalled = 0))". Unexpected character at position. Please help.
What happens when you change the DetectCondition to
<ExePackage
Id="AccessRuntime2013"
DetectCondition="MsAccessInstalled ~= "Outlook.Application.15" AND MSOffice2013RuntimeInstalled = 0"
... />
You can also test your conditions by making some test util:Condition tags in your bootstrapper.
<util:Condition Message="MSAccessInstalled condition failed">MsAccessInstalled ~= "Outlook.Application.15"</Condition>
<util:Condition Message="MSOffice2013RuntimeInstalled condition failed">MSOffice2013RuntimeInstalled = 0</Condition>
Run your bootstrapper and see if either condition fails. Do remember to remove these conditions once you're done testing as they will cause issues if put into production.

Setting property value in Wix

I am trying to set a property to the installation directory. The following code doesnt work
<SetProperty Id="TALKMANSERVICE_MESSAGESCONFIG" Before="InstallInitialize" Value="[INSTALLDIR]\services\MessagesConfig.xml" />
So when can I set this property to the installation directory that has been selected by the customer?
Schedule it in the InstallExecuteSequence after CostFinalize. This is needed because you are using the value [INSTALLDIR] which is a directory table entry ( assuming it exists in your MSI and isn't called something else like INSTALLLOCATION ) and this entry won't be resolved to a property until after file costing.
Also, why do you need this property? You can use [#filekey] to have the installer tell you the full path to the file. See: Formatted
•If a substring of the form [#filekey] is found, it is replaced by the
full path of the file, with the value filekey used as a key into the
File table. The value of [#filekey] remains blank and is not replaced
by a path until the installer runs the CostInitialize action, FileCost
action, and CostFinalize action. The value of [#filekey] depends upon
the installation state of the component to which the file belongs. If
the component is run from the source, the value is the path to the
source location of the file. If the component is run locally, the
value is the path to the target location of the file after
installation. If the component has an action state of absent, the
installed state of the component is used to determine the [#filekey]
value. If the installed state of the component is also absent or null,
[#filekey] resolves to an empty string, otherwise it resolves to the
value based upon the component's installed state. For more information
about checking the installation state of components, see Checking the
Installation of Features, Components, Files.

Error Getting Property

So.. I've got this CA
<CustomAction Id="InstallSetProp" Property="CustomActionData" Value="<some other data that's formatted exactly the same> /webconftmploc="[WEBCONFIGTMPLOC]"" />
However, when this CA is called, a message box is shown saying "Error Getting Property" which is bogus since the property is correctly set and accessible later on. (And does nothing except mess up my attempts to fully automate installation) I'm running the .msi through a bootstrapper that switches /qr to help with this.
The message box error is not shown when /webconftmploc="[WEBCONFIGTMPLOC]" is removed, for the record [WEBCONFIGTMPLOC] is either an absolute file path or "Not Set" and I'm wondering if there's any special reason why this behaviour can occur.
However, I'm much more interested in any possible way to suppress or fix this action, of-course.
That CustomAction only sets a property. It is not possible for it to show an error message. If any of the properties were not defined they would just resolve to blank. Something else must be showing the error message.
However, it appears that you are trying to pass data to a deferred custom action due to your use of the specially named CustomActionData. That isn't quite the way to use CustomActionData though. Instead, the Property attribute should be set to the Id of the CustomAction that you want to pass data too. Say the custom action that uses that property value is something like:
<CustomAction Id='MyDeferredCustomAction' Execute='deferred' ... />
To pass it the string you are trying to send, you could write:
<CustomAction Id="InstallSetProp"
Property="MyDeferredCustomAction"
Value="<some other data that's formatted exactly the same> /webconftmploc="[WEBCONFIGTMPLOC]"" />
Notice that the second custom action is setting a property with the same name as the deferred custom action: MyDeferredCustomAction. The MyDeferredCustomAction can access the value <some other data that's formatted exactly the same> /webconftmploc="value_of_WEBCONFIGIMPLOC_goes_here" via the magical CustomActionData property. You can read more about that here: http://msdn.microsoft.com/en-US/library/2w2fhwzz(v=VS.80).aspx