Conditionally set single WiX Property to different values - wix

I have an installer that deploys a website as either a SSL or non-SSL IIS site depending on whether a property is set or not. I've been asked to add the option to set the port, which isn't a problem, but I'd like to set the port to the default values (80 or 443) if the value isn't set.
I tried something like:
<SetProperty Id="OUTPORT" Before="InstallFiles" Value="80"><![CDATA[SSL=0]]></SetProperty>
<SetProperty Id="OUTPORT" Before="InstallFiles" Value="443"><![CDATA[SSL=1]]></SetProperty>
But, obviously, WiX complains about the custom action having the duplicate ID SetOUTPORT.
Am I jumping down another WiX-shaped rabbit hole here?

The accepted answer is not correct in needing to convert to writing out in full the custom action and sequencing (no longer?).
As per documentation for WiX 3, SetProperty Element
Without setting SetProperty\#Action
<SetProperty Id="OUTPORT" Before="InstallFiles" Value="80"><![CDATA[SSL=0]]></SetProperty>
<SetProperty Id="OUTPORT" Before="InstallFiles" Value="443"><![CDATA[SSL=1]]></SetProperty>
Duplicate symbol 'CustomAction:SetInstallFiles' found
Action. String. By default, the action is "Set" + Id attribute's value. This optional attribute can override the action name in the case where multiple SetProperty elements target the same Id (probably with mutually exclusive conditions).
The following works without having to change to writing out custom actions.
<SetProperty Action="SetInstallFiles0" Id="OUTPORT" Before="InstallFiles" Value="80"><![CDATA[SSL=0]]></SetProperty>
<SetProperty Action="SetInstallFiles1" Id="OUTPORT" Before="InstallFiles" Value="443"><![CDATA[SSL=1]]></SetProperty>
It works in WiX 3.7, and I am not sure about which first version it is available from.

SetProperty now supports the Action attribute to let you specify custom action ids when you want to have multiple SetProperty elements for the same property with different conditions.

Related

Wix Installer - Getting data from a Property

I am using Wix to make an installer and I was wondering how I indirectly get a property's value.
Like if I have a Property WIXUI_INSTALLDIR that is preset with the INSTALLFOLDER value
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
and this Property then is changed through a a Dialog from user input and I after that would want to get what the user changed the path to, how do I get the "value" out of WIXUI_INSTALLDIR ?
I would like to send this value (a string I suppose) to either the registry or a custom action.
If I try [WIXUI_INSTALLDIR] I get a warning for illegal indirection if used with a custom action and if I try to send it to registry it just becomes "[WIXUI_INSTALLDIR]" as a string.
EDIT:
My problem is when also using my own made up properties like this:
Property Id="MyOwnProperty" Value="Hello There"
and let's say a Dialogue changes the value of MyOwnProperty, how do I the access the new Value ? Like sending [MyOwnProperty] to a CustomAction as parameter will only get "[MyOwnProperty]" as a literal string.
Try getting the value of the Property (or Directory) that WIXUI_INSTALLDIR references. In this case, use [INSTALLFOLDER] in the formatted field where you'd like the value.

Show message when condition within Feature fails

When I add a Condition within a Feature to assure that IIS is installed, it is working as expected (it searches installed IIS, when feature is selected. No check, when feature is not selected):
<Feature Id="feat.WebApplication"
Title="Web Application"
Level="1"
ConfigurableDirectory="DIR.WEBAPP">
<Condition Level="0">
<![CDATA[Installed OR (IISMAJORVERSION AND IISMAJORVERSION >= "#7")]]>
</Condition>
<!-- ... -->
</Feature>
But - as documented in Condition Element - it is not allowed to have a message within the condition. So the installation silently fails, whereas it shows a message when the condition is placed directly in the Product node.
How can I show a message also for conditions within features?
As I understand the Condition node, after reading about the Level attribute of the Feature Element,
Sets the install level of this feature. A value of 0 will disable the feature. Processing the Condition Table can modify the level value (this is set via the Condition child element). The default value is "1".
by using Condition within feature you get the ability to disable or enable features depending on its own value for Level, because you can override it if the condition matches with the value of the Level attribute of the condition.
So the best would be to add some text about the precondition to the feature Description.

Custom action to set a property after a failed RegistrySearch is not running

The aim is that if the value isn't found in the registry then I want to assign a default value and then have that value display as the default value in a field in the installer UI. The default value I actually want to use is [ComputerName] but obviously I can't use [ComputerName] directly in the property value attribute because it will give me errors on compiling, specifically:
warning CNDL1077: The 'MYPROPERTY' Property contains '[ComputerName]'
in its value which is an illegal reference to another property. If
this value is a string literal, not a property reference, please
ignore this warning. To set a property with the value of another
property, use a CustomAction with Property and Value attributes.
I want to get it working with plain text before I even try [ComputerName] but so far I can't even get that working.
In my project I have a Product.wxs file which contains the Product element, lots of custom actions (most of which are running fine but they're all running significantly later) and the following elements which are not cooperating and which are all siblings under the Product element.
Property definition and registry search:
<Property Id="MYPROPERTY" Value="ADefaultValue">
<RegistrySearch Id="MyProperty" Type="raw" Root="HKLM" Win64="$(var.Win64)"
Key="Software\MyCompany\MyApplication" Name="MyProperty" />
</Property>
Custom action definition:
<CustomAction Id="SetMyPropertyDefault" Property="MYPROPERTY" Value="MyCustomValue" Execute="immediate"/>
Custom action execution:
<InstallExecuteSequence>
<Custom Action="SetMyPropertyDefault" After="AppSearch"><![CDATA[MYPROPERTY="ADefaultValue"]]></Custom>
</InstallExecuteSequence>
It just will not work for me at all.
For the custom element content I have tried:
<Custom Action="SetMyPropertyDefault" After="AppSearch"><![CDATA[MYPROPERTY="ADefaultValue"]]></Custom>
<Custom Action="SetMyPropertyDefault" After="AppSearch">1</Custom> // I thought this would always run the custom action.
<Custom Action="SetMyPropertyDefault" After="AppSearch">NOT MYPROPERTY</Custom> // Back when I wasn't using the default value on the property at all.
The result is always the same, I'm still getting "ADefaultValue" showing up in the UI, never the alternate "MyCustomValue".
According to every blog and SO post I've seen I'm doing exactly what I should be doing except clearly I'm missing something.
Any ideas?
UPDATE/Answer:
The piece of information that I was missing which was provided by #sutarmin-anton was that InstallUISequence runs before InstallExecuteSequence (seems counter-intuitive to me but there you go).
But as it happened I didn't need to explicitly duplicate the custom action call in each of the install sequence elements, instead I used the SetProperty element.
So now I've got the following in my Product.wxs as children of the Product element:
<Property Id="MYPROPERTY">
<RegistrySearch Id="MyProperty" Type="raw" Root="HKLM" Win64="$(var.Win64)" Key="Software\MyCompany\MyApplication" Name="MyProperty" />
</Property>
<SetProperty Id="MYPROPERTY" After="AppSearch" Value="[ComputerName]">NOT MYPROPERTY</SetProperty>
It now runs the SetProperty after AppSearch in both InstallUISequence and InstallExecuteSequence, but the second time it runs the NOT MYPROPERTY will come out false so it doesn't get reset, and of course if it's run in quiet mode it'll still work correctly.
When you going through installer UI, installation is in InstallUISequence. InstallExecuteSequence runs after all UI events. This is cause of you have not seen "MyCustomValue". To change your property before UI sequence you should place your custom action in "InstallUISequence".
By the way, why don't you set default value of your property to "MyCustomValue"? Then, if AppSearch wont find value in regisrty, it just leave default value that you are trying to set manually.
You may be overcomplicating things. The MYPROPERTY value will not be set at all if you don't set a default. So then you call your CA to set it if 'NOT MYPROPERTY'
I see that you've tried this, and I'd say it's the correct approach that I'd try to diagnose rather than try something else. A verbose log would be invaluable. Do a:
msiexec /i [path to msi] /l*vx [path to a text log file]
and see what CA is called, what AppSearch does, property values etc.
Your original comment of "I can't use [ComputerName] - if that's the problem why not tell us what happened and maybe there is a solution that doesn't require all this. What's the compile error, for example?

wix: setting multiple value depending on a specific condition

I've got different installation modes. Depending on the parameters I do things like:
<Property Id="PROP1" Value="Value1" />
<SetProperty Id="PROP1" Before="CostFinalize" Sequence="execute" Value="Value2"></SetProperty>
The problem is that I've got more than 2 options, when I'm adding them I'm getting.
Duplicate symbol 'CustomAction:SetPROP1' found.
Is there a way to have some sort of switch statement or how do you handle multiple conditionals?
Another trouble is, I've got multiple variables set depending on the value (about 10 right now) and it's very cumbersome to list them all with absolutely the same code
<SetProperty Id="PROP2" Before="CostFinalize" Sequence="execute" Value="Value2"></SetProperty>
<SetProperty Id="PROP3" Before="CostFinalize" Sequence="execute" Value="Value3"></SetProperty>
etc
Is there any way to make it like:
<Condition val="...">
<setProperty.../>
<setProperty.../>
<setProperty.../>
</Condition>
Thanks!
First of all, try to re-think the architecture of your installation program. Is it really necessary to set all those properties based on the same condition? Or maybe it's better to "condition"-ize the appropriate features and components in a more plain way?
Let's get back to the technical side of your question. The SetProperty element is just a shortcut which is "all-in-one" solution for defining a custom action which sets a property and scheduling it appropriately. It is true that you can't use it to set the same property to different value, because there's no ID attribute of the SetProperty element itself.
Instead, use the good old style of defining a custom action and scheduling it manually:
<CustomAction Id="SetProp11" Property="PROP1" Value="Value1" />
<CustomAction Id="SetProp12" Property="PROP1" Value="Value2" />
...
<InstallExecuteSequence>
<Custom Action="SetProp11" After="...">your condition here</Custom>
<Custom Action="SetProp12" After="...">your condition here</Custom>
...
</InstallExecuteSequence>
This definitely adds extra typing work and makes your code less readable, but this way you can work your problem around. However, let me emphasize once again - the fact that you have to invent workarounds means that the code starts to smell and it might make sense to re-think it through.
And I'm not aware about the way to set a number of properties in a bunch, like in switch statement. Alternatively, technically you can create a e.g. C# custom action and let it do the job for all the properties at once.
Hope this helps.

Set property value based on condition in WiX

I searched through several questions at Stack Overflow, but nothing helped me. The problem is:
I look in the registry for some value (I know how to do that). I know how to set property. But I cannot find the way how to write this expression in WiX. This is what I want to write in pseudocode:
if(registryvalue contains substring1)
set property to value1
if(registryvalue contains substring2)
set property to value2
This condition must be evaluated at runtime. Is there a way to write this condition? What would some sample code look like?
You can use a type 51 custom action to set the property:
<CustomAction Id="SET_VALUE1" Property="TEST_PROPERTY" Value="value1" />
<CustomAction Id="SET_VALUE2" Property="TEST_PROPERTY" Value="value2" />
Use the condition when you call the custom action in install sequences:
<Custom Action="SET_VALUE1" After="AppSearch">Not Installed AND (REG_VALUE="substring1")</Custom>
<Custom Action="SET_VALUE2" After="AppSearch">Not Installed AND (REG_VALUE="substring2")</Custom>
Or you can write the custom actions in managed code like C#, and schedule it after AppSearch in case you have many comparisons.