How to run custom action based on condition? - wix

I'm trying to run a custom action (delete a certain file) based on the windows version.
I know how to check for the windows version:
<Condition Message="Windows version xxx required...">
<![CDATA[Installed OR (VersionNT >= 600)]]>
</Condition>
However, I do not want to display a message, but delete a file. I can't find an example on how to use such a condition to run oder not to run a custom action!

You need to specify the condition inside the Custom element which runs your custom action. (This allows you to run the custom action multiple times in different locations in your sequence and with different conditions each time if desired).
Example:
<InstallExecuteSequence>
<Custom Action="CreateRegistryEntries" After="CostInitialize">
NOT Installed AND NOT PATCH
</Custom>
</InstallExecuteSequence>

Related

Failing condition wix

I am trying to skip installations in the following cases:
Windows OS type is = desktop OS
if HKLM\SYSTEM\CurrentControlSet\Services\MyService MYKEY= myValue
if REG HKLM\SYSTEM\CurrentControlSet\Services\MyService = DisplayName is present
AND HKLM\SYSTEM\CurrentControlSet\Services\MyService MYKEY is not present
while installation it went well, but while installation my feature is missing from installation.
Am I doing anything wrong in putting condition?
<Property Id="MYKEY" Secure="yes">
<RegistrySearch Id="MyKey"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\Services\MyService"
Name="mykey"
Type="raw" />
</Property>
<Property Id="MYSERVICE" Secure="yes">
<RegistrySearch Id="MYSERVICE"
Root="HKLM"
Key="SYSTEM\CurrentControlSet\Services\MyService"
Name="DisplayName"
Type="raw" />
</Property>
<Feature Id="MyFeature" Level="" Display="" Title="" Description="" AllowAdvertise="no" ConfigurableDirectory="INSTALLDIR">
<MergeRef Id="MyFeature" Primary="yes"/>
<Condition Level="0">((MsiNTProductType=1) OR
(MYKEY="MyValue") OR
(MYSERVICE="MyService" AND MYKEY=""))</Condition>
</Condition>
</Feature>
NOTE: The below has not been tested extensively - conditions are notorious for being difficult to get right. Testing conditions requires real-world testing. A few more links:
Condition debugging
WiX launch conditions
Wix Tools update uses old custom actions (example of complex conditions)
How to add a WiX custom action that happens only on uninstall (via MSI)?
When either of those three "sub"-conditions are true, what do you want to achieve?
Abort Setup: Abort the whole setup? (LaunchConditions)
Configure Features: Prevent or enable installation of specific feature(s)? (Feature conditions)
This difference is obviously crucial - and we must know to be able to answer. Your WiX source snippet currently shows the conditions used as feature conditions. I have a feeling this is not what you want.
LaunchConditions: In order to abort the whole setup if one of these conditions are true, you could try to use LaunchCondition entries. Instead of making one complicated condition, you can just split them in three different entries that each check if the setup should be aborted - each entry for a different and specific reason. I suggest you add these LaunchCondition entries after your Package element in your WiX source file:
<Condition Message="Aborting setup: Server OS required for installation.">Installed OR MsiNTProductType=1</Condition>
<Condition Message="Aborting setup: State reason for abortion.">Installed OR MYKEY="MyValue"</Condition>
<Condition Message="Aborting setup: State reason for abortion.">Installed OR (MYSERVICE="MyService" AND MYKEY="")</Condition>
These entries will make it into the LaunchCondition table of your compiled MSI file.
LaunchConditions must always evaluate to true for the setup to be able to install / run.
Accordingly, the Installed parts of the conditions above are there to ensure that the condition is always true after installation - so you don't get the situation that the setup will not allow itself to be uninstalled or repaired because a launch condition is not met. The condition: Installed - will always be true except for a fresh install and major upgrades.
NOTE: I am not sure whether launch conditions can cause trouble during administrative installations. I don't think they do (an administrative installation features its own installation sequences). I will test and verify tomorrow. Adding OR ACTION="ADMIN" should make the launch condition true on any box when administrative installation is run.
Feature Conditions: If you don't want to abort the setup, but rather want to control feature installation status based on evaluating these conditions, you need to use the feature conditions concept instead of the launch condition concept.
When you set the Feature level to 0 in your WiX source, the feature is not show in the setup GUI and it is not going to be installed by default either. A feature condition can change this and set the feature to install if the condition evaluates to true.
You can also go the other way around and set the feature level to 1 as default (this should install the feature) and then use a feature condition to set its Feature level to 0 - if you don't want the feature installed - when the condition is true.
There are some further details under "Quick Mockup" here: WIX If...else condition using registry.
In the below WiX snippet we set a feature to install by default (Level="1") and then we use a feature condition to set the feature to not install if its associated condition evaluates to true (this is a multi-part condition). So once the condition evaluates to true we assign feature Level="0" (which means do not install feature and hide it from the setup GUI):
<Feature Id="MyFeature" Level="1"> <!--Default to install feature-->
<Condition Level="0"> <!--Do not install feature if condition is true-->
((MsiNTProductType=1) OR (MYKEY="MyValue") OR (MYSERVICE="MyService" AND MYKEY="") AND (NOT ACTION="ADMIN"))
</Condition>
</Feature>
The AND (NOT ACTION="ADMIN") part is to force the feature to be installed in an administrative installation. It effectively shuts off the other conditions from evaluating to true if the setup is run in administrative install mode - which would cause the feature to not be installed during the admin install. This last part I have to test tomorrow.
UPDATE: Testing indicates that any feature set to Level=0 as default will not be extracted during an administrative install at all,
regardless of any feature conditions setting the feature to install. I
guess the tentative conclusion is to not set any features to
Level=0, but set Level=1 and then set them to Level=0 with a
feature condition that evaluates to true. This way the feature may be
hidden in a regular installation, but all features - with associated
files - are extracted during admin installation. The AND (NOT ACTION="ADMIN") part of the condition appears to not be needed.
Leaving the sample above as it is for now.
Links:
WIX If...else condition using registry
How to execute custom action only in install (not uninstall)
How to add new framework version in Installment Requirement page of InstallShield?

Wix: Executing installed exe as a first action on Uninstall

In my msi, I have to call the installed exe file with some parameters, as a very first action of uninstall. Here is the code:
<CustomAction Id="UnRegisterOnUninstallApplication"
Execute="immediate"
FileKey="MyProgram.exe" ExeCommand="/unregister" Return="asyncNoWait" />
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize"/>
<Custom Action="UnRegisterOnUninstallApplication" Before="UnpublishComponents" >Installed AND NOT UPGRADINGPRODUCTCODE</Custom>
</InstallExecuteSequence>
Although, it is scheduled Before UnpublishComponents, but issue is, at some computers, custom action is called during or after dependency dlls are uninstalled and so MyProgram.exe crashes here.
This is something seems unpredictable...
Can anyone please guide, if I'm missing something or doing something wrong???
Thanks a bunch.
There are several things incorrect here:
The design issue is that you shouldn't be running code to register or unregister. The recommended way is to capture the registry entries and add them as registry entries in the same component as that binary. Then it all just works.
Your custom action is asyncNoWait, and that means the uninstall continues while the program runs. If it takes a long time for some reason, or simply doesn't get enough of the processor, then yes, files may have been removed by the time it runs.
It's an immediate custom action, so it can run and start unregistering as the uninstall proceeds. However if the uninstall fails and rolls back the deleted registration will not be restored, so you'll end up with a broken product still installed, those registration entries will stay removed. It should be a deferred custom action and return = ignore or check, depending on whether you care if the program fails.
I might schedule the action before 'RemoveFiles' so that no dependent dlls have been removed before your custom action gets to run.

Run ExeCommand in customAction as Administrator mode in Wix Installer

I am new to wix installer. I have developed a set-up using wix installer for my application and I need to execute a Custom Action to run a command in cmd.exe. In XP it works fine. But in Windows 8 & 7 the cmd prompt needs to be run as administrator.
I have googled and found the keywords Elevated Privileges and impersonate might help me.
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated"></Package>
As you can see above, I used the InstallScope attribute set to perMachine, and I have used Impersonate="No" in the CustomAction element:
<CustomAction Id='comReg' Directory='INSTALLLOCATION' Impersonate='no'
ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" "[INSTALLLOCATION]myProduct.dll" /codebase' Return='check' />
But I didn't get any changes while installating. I need the command prompt to open and run the above command in Administrator Mode.
And can anyone please tell me about these keywords "Elevated Privileges & impersonate"
<InstallExecuteSequence>
<Custom Action='comReg' After='InstallFinalize'>NOT REMOVE</Custom>
<Custom Action='comUnreg' Before='RemoveFiles'>REMOVE</Custom>
</InstallExecuteSequence>
How to do it?
The wix documentation here explains the Impersonate attribute:
This attribute specifies whether the Windows Installer, which executes as LocalSystem, should impersonate the user context of the installing user when executing this custom action. Typically the value should be 'yes', except when the custom action needs elevated privileges to apply changes to the machine.
You also need to understand the difference between deferred and immediate custom actions. See the Execute attribute on the same help page:
This attribute indicates the scheduling of the custom action. This attribute's value must be one of the following:
deferred
Indicates that the custom action runs in-script (possibly with elevated privileges).
immediate
Indicates that the custom action will run during normal processing time with user privileges. This is the default.
At present your custom action is immediate, which means it is running with user privileges. See this blog post for lots of details, but particularly:
Any immediate custom actions impersonate the invoking user. Before Windows Vista this wasn't a problem since at this point the installing administrative user had a privileged token. With the introduction of UAC in Windows Vista the default administrative token with UAC enabled is a filtered token and does not hold all privileges. Since immediate custom actions are not supposed to modify machine state - only to gather state data and schedule custom actions to run deferred - this still shouldn't be a problem. After all, at this point the generation of the installation and rollback scripts is all that should be going on.
You should never modify machine state with an immediate custom action. Use a deferred one, and keep impersonate to no, and it should work:
<CustomAction Id='comReg' Directory='INSTALLLOCATION' Execute='deferred' Impersonate='no' ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" "[INSTALLLOCATION]EAWordImporter.dll" /codebase' Return='check' />
EDIT: Schedule the custom action using the InstallExecuteSequence element:
<InstallExecuteSequence>
<Custom Action='comReg' Before='InstallFinalize'/>
</InstallExecuteSequence>

Why doesn't this silent launch work in WIX?

I have the following command running at the end of my package install for an application.
<Property Id="WixShellExecTarget" Value="[INSTALLDIR]RCR.VDS.exe" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA"
DllEntry="WixShellExec" Impersonate="no" />
I can't use [#myApplication] because I run heat on my output folder on my build server so I don't know the auto generated id of my application. Any ideas on how to silently run my application after the install?
The log file shows this for the command line section
******* CommandLine: **********
MSI (c) (30:74) [09:47:14:156]: Note: 1: 2203 2: VDSInstall.msi 3: -2147287038
MSI (c) (30:74) [09:47:14:156]: MainEngineThread is returning 2
Please see: How To: Run the Installed Application After Setup
If you want the custom action called during a silent install add:
<InstallExecuteSequence>
<Custom Action="LaunchApplication" After="InstallFinalize">SOMECONDITION</Custom>
</InstallExecuteSequence>
Note SOMECONDITION should be an expression that checks the EXE is installed and the user wants the program to be launched.
The are a copy things you can consider:
The identifier from heat.exe will be stable. So you can use the ugly identifer in your [#UglyFileId1234abcef45612345asdf] custom action.
a. You could also apply a XSLT to transform the heat output for the executable file's Id to something nicer than the ugly identifier. Depends how readable you want the launch custom action to be.
If you want the executable launched silently then you'll probably want the Quite Execution custom action instead of the Shell execute custom action that "LaunchApplication" uses.

WiX uninstall - close application before Restart Manager

I have an installer done with WiX. When it's done installing, it starts an application that injects some code in the Explorer process.
Currently when I uninstall, the Restart Manager kicks in and offers to shut down my application and Explorer. Instead of that I want to close my application manually (this is done by running it again with -exit on the command line). I have a custom action that does it.
Here's what I tried so far:
<CustomAction ExeCommand="-exit" FileKey="MyApp.exe" Id="CloseMyApp" Impersonate="yes" Return="ignore" />
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize" />
<Custom Action="CloseMyApp" Before="RemoveFiles" />
</InstallExecuteSequence>
This doesn't work. The action is done way after the Restart Manager session. So the Restart Manager pops up and asks to close my app and Explorer. The action runs later, but by then the app is already gone.
So then I tried this:
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize" />
<Custom Action="CloseMyApp" Before="RemoveExistingProducts" />
</InstallExecuteSequence>
This also doesn't work. The action is done too late still. I also get "warning LGHT1076 : ICE63: Some action falls between InstallInitialize and RemoveExistingProducts.".
So basically - how do I execute my custom action during uninstall and before the Restart Manager session?
I'm guessing if I use Impersonate="no" it might run at the right time, however that's not an option. That's because the new process must run for the same user as the process that has to close because it looks up its window and sends messages. That's much trickier to do if the processes belong to different users.
Any ideas?
You would need the CloseMyApp custom action to run before InstallValidate since that is when the restart manager is processed (doc). Alternatively, you could disable restart manager with MSIDISABLERMRESTART or MSIRESTARTMANAGERCONTROL Properties.