Launch after install, with no UI? - installation

How do I launch my application after install with no UI (or in quiet mode)? Thanks!
I had a installer with UI which has an option to run after install. Now I want my application to updates itself by downloading and running the new version of installer in quiet mode, but after updating done, it won't launch again.

From the msdn topic on sequencing custom actions:
As in the case of standard actions,
custom actions that are scheduled in
the InstallUISequence or
AdminUISequence run only if the
internal user interface is set to the
full level.
So I guess your custom action is scheduled in a UI sequence, not in InstallExecuteSequence. Try scheduling your custom action in the InstallExecuteSequence like this:
<InstallExecuteSequence>
<Custom Action='LaunchApplication' After='InstallFiles'/>
</InstallExecuteSequence>
where "LaunchApplication" should be replaced by the Id of your CustomAction element.
edit: I looked at the instructions that you followed, and I don't see the custom action for launching the application being scheduled in any sequence. It is only triggered from a UI action (clicking the Finish button). This explains why it is never executed during a silent install.
edit: full sample (it's a bit sloppy as it also tries to execute the custom action on uninstall, repair etc. but for some reason I couldn't get the "NOT Installed" condition to work)
<?xml version='1.0' encoding='utf-8'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product
Name='ProductName'
Id='*'
Language='1033'
Version='0.0.1'
Manufacturer='ManufacturerName' >
<Package
Keywords='Installer'
Description='Launch application demo'
Manufacturer='ManufactererName'
InstallerVersion='100'
Languages='1033'
Compressed='yes'
SummaryCodepage='1252'/>
<Media Id='1' Cabinet='test.cab' EmbedCab='yes'/>
<Directory Id='TARGETDIR' Name="SourceDir">
<Directory Id='ProgramFilesFolder'>
<Directory Id='TestFolder' Name='Test' >
<Component Id="ExeComponent" Guid="*">
<File Id="ExeFile" Source="c:\windows\notepad.exe" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id='Complete'
Display='expand'
Level='1'
Title='Test'
Description='Test'>
<ComponentRef Id="ExeComponent" />
</Feature>
<InstallExecuteSequence>
<Custom Action='LaunchInstalledExe' After='InstallFinalize'/>
</InstallExecuteSequence>
<CustomAction Id="LaunchInstalledExe"
FileKey="ExeFile"
ExeCommand=""
Execute="immediate"
Impersonate="yes"
Return="asyncNoWait" />
</Product>
</Wix>

In my final solution I used two properties, one for UI (LAUNCH_APP_ON_EXIT), one for command line arguments (UPDATING_AUTOMATICALLY).
I have to do this because if I run the CustomAction after InstallFinalize in full UI mode, the application would start before you click the "Finish" button.
Now I can call setup.exe /qn UPDATING_AUTOMATICALLY=1 in my program to update.
Here is it all:
<Property Id="LAUNCH_APP_ON_EXIT" Value="1" />
<Property Id="UPDATING_AUTOMATICALLY" Value ="0" />
<CustomAction Id="LaunchApplication" FileKey="mainExecutableFile" ExeCommand="" Execute="immediate" Impersonate="yes" Return="asyncNoWait" />
<UI>
<!-- explainations: http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/ -->
<UIRef Id="MyWixUI_InstallDir" />
<UIRef Id="WixUI_ErrorProgressText"/>
<Publish Dialog="MyExitDialog" Control="Finish" Order="1" Event="DoAction" Value="LaunchApplication">LAUNCH_APP_ON_EXIT</Publish>
</UI>
<InstallExecuteSequence>
<Custom Action='LaunchApplication' After='InstallFinalize'>UPDATING_AUTOMATICALLY = 1</Custom>
</InstallExecuteSequence>

I would assume that you are launching your app from a custom action, which is triggered through a property bound to the checkbox. If that is the case, you can try specifying that property as a command line argument to setup.exe. Say, if your custom action is bound to the MSI property LAUNCH_NEW_VERSION, you can call setup.exe like this:
setup.exe /q LAUNCH_NEW_VERSION=1
The standard setup bootstrapper should pass that property/value to the MSI engine. If it doesn't, you might consider invoking the .msi directly instead of calling the bootstrapper exe to run your installer.

This is the approach I took.
<Property Id="WixShellExecTarget" Value="[#(the id of your exe here)]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
This will execute which ever file id you enter in the Value. The [# ] is needed. I used this and ran it via the UI but you should be able to call this custom action anywhere and it work.

Related

Unable to remove previous versions of MSI. Multiple entry's show up in control panel

I am not sure if i am missing something or i just plain dumb, the issue i am having related to uninstalling a MSI. Basically i am building a app, and using WIX to create the MSI installer. What is happening is that i am able to install a previous version of the app but not upgrade to a newer version MSI. E.g, when i click/install the newer version MSI then the older MSI, both MSI will be installed and visible in control panel(MyApp 1.5.0, MyApp 1.6.0).
I am pretty sure i have the "MINORUPGRADE/MAJORUPGRADE" along with the RemoveExistingProducts Action configured properly but this issue still happens.
I tried modifying the MINORUPGRADE/MAJORUPGRADE values and the RemoveExistingProducts property but still get the same behavior.
My WIX config looks like this (without the Directory/paths...)
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="*" Language="1033" Manufacturer="MyApp" Name="MyApp $(env.APP_BASE_VERSION)" UpgradeCode="$(env.UPGRADE_CODE)"
Version="$(env.APP_BASE_VERSION)">
<Package Compressed="yes" InstallerVersion="200" InstallScope="perMachine" InstallPrivileges="elevated" Description="MyApp $(env.APP_VERSION) Installer"
Comments="" Manufacturer="MyApp" />
<Property Id="MsiLogging" Value="v!" />
<MediaTemplate EmbedCab="yes" CompressionLevel="$(env.COMPRESSION_LEVEL)"/>
<Icon Id="icon.ico" SourceFile="$(env.STATIC_RESOURCE_PATH)\icon.ico" />
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
<Upgrade Id="$(env.UPGRADE_CODE)">
<UpgradeVersion
Property="MAJORUPGRADE"
Minimum="0.0.0.0"
IncludeMinimum="yes"
Maximum="$(env.APP_BASE_VERSION)"
IncludeMaximum="no"
IgnoreRemoveFailure="no"
MigrateFeatures="yes" />
<UpgradeVersion
Property="MINORUPGRADE"
Maximum="$(env.APP_BASE_VERSION)"
Minimum="$(env.APP_BASE_VERSION)"
IncludeMinimum="yes"
IncludeMaximum="yes"
/>
</Upgrade>
...
<CustomAction Id="Remove_Roaming_MyApp" Directory="TARGETDIR" ExeCommand="cmd.exe /C "rmdir /s /q "[AppDataFolder]\MyApp""" Execute="deferred" Return="ignore" HideTarget="yes" Impersonate="no" />
<Property Id="WixShellExecTarget" Value="[#MyAppEXE]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<util:CloseApplication Id="CloseApp" Target="MyApp.exe" RebootPrompt="no" CloseMessage="yes"/>
<CustomAction Id="Kill_MyApp_instances"
Directory="TARGETDIR"
ExeCommand="taskkill.exe /IM MyApp.exe /F"
Execute="deferred"
Return="ignore" HideTarget="yes" Impersonate="no" />
<!-- This will create a log in the Temp folder of the user profile by default. NOTE: this is not the full log! The MSI will need to be ran with `/l*v <destination file>` -->
<CustomAction Id="CopyLog_partial"
ExeCommand="cmd /c copy "[MsiLogFileLocation]" "%SystemDrive%\Windows\Temp\MyApp-msi.log""
Directory="TARGETDIR"
Impersonate="no"
Execute="commit"
Return="ignore" />
<CustomAction Id="CopyLog_full"
ExeCommand="cmd /c copy "[MsiLogFileLocation]" "[LocalAppDataFolder]\Temp\MyApp-msi.log""
Directory="TARGETDIR"
Impersonate="no"
Execute="immediate"
Return="ignore" />
<InstallExecuteSequence>
<RemoveExistingProducts Before="InstallValidate" />
<Custom Action="WixCloseApplications" Before="InstallValidate" />
<Custom Action="Kill_MyApp_instances" After='InstallInitialize'></Custom>
<Custom Action="LaunchApplication" After='InstallFinalize'>NOT Installed</Custom>
<Custom Action="CopyLog_partial" After="PublishProduct" />
<Custom Action="CopyLog_full" OnExit="success" />
</InstallExecuteSequence>
<Feature Id="ProductFeature" Title="SetupProject1" Level="1">
<ComponentGroupRef Id="ELECTRON_FRAGMENTS"/>
<ComponentRef Id="Remove_MyApp_Roaming_comp" />
<ComponentRef Id="Remove_uninstallCache_folder" />
<ComponentRef Id="Remove_MyApp_programFiles_comp" />
<ComponentRef Id="Shortcut_startMenu" />
</Feature>
</Product>
</Wix>
The intended behavior is to remove the previous MSI or better yet all versions installed during the installation process of the MSI. I know this can be done with a CustomAction but i was wondering if theres a more elegant way to do this?
Summary: When you get two entries in Add / Remove Programs the major upgrade has failed. I suggest you comment out all major upgrade
constructs and try to get a heartbeat with the simplest constructs
available - explained below.
Major Upgrade: You have used old constructs to implement your major upgrade. There is a newer and simple way, like this:
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
This is sort of like a "template" implementing the major upgrade with the least amount of fuzz by just using "normal options" or simplified options if you like. There is no need to add your own RemoveExistingProducts entry when you use this template, in fact that will probably yield a "duplicate entry / symbol" on compile:
Add the MajorUpgrade element above.
Comment out the entire Upgrade element.
Comment out the RemoveExistingProducts element.
Older Constructs: The MajorUpgrade element will be enough to implement a working major upgrade, but you can still use the old WiX constructs (Upgrade and UpgradeVersion elements) to obtain more fine-grained control of the authoring of the Upgrade table. It is this table which defines how existing installations are to be handled. The upgrade table identifies related products by matching upgrade codes and then performs whatever action is defined for that scenario in the Upgrade table itself.
Previous Answers: There are several older answers on this topic, please see the following:
Doing Major Upgrade in Wix creates 2 entries in Add/Remove Programs
Adding entries to MSI UpgradeTable to remove related products (this shows how to use both the newer template construct AND the older WiX element for "fine-grained" control of Upgrade table).
A Few More Links:
Upgrading a WiX generated package with major version zero
How to prevent Wix from installing an older version?
Wix UpgradeVersion
Checking for Oldies
UPDATE:
Unable to remove previous versions of MSI. Multiple entry's show up in control panel
WIX does not uninstall older version (potential causes of failed major upgrade)

Problem with Wix uninstall using CustomAction

I've created a very simple MSI which copies some files to the ProgramFiles directory and while installing calling to custom actions found in a binary written in C#.
While installing, I can easily call any custom action I want. For example I've created an installation step where the user should enter a license, and after confirming the license it is checked against a server using logic written inside C# custom action.
But, when uninstalling, every time I add a custom action (even if it does nothing but returning Success), I get error that the installation failed.
This is how I use the uninstalling step:
<InstallExecuteSequence>
<Custom Action='TestUninstallation' After='MsiUnpublishAssemblies'>REMOVE="ALL"</Custom>
</InstallExecuteSequence>
where TestUninstallation is defined as following:
<CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no" BinaryKey="TestCustomAction" DllEntry="Uninstall" />
The property DllEntry equals Uninstall which is a C# method which only returns Success.
After installation is completed, I'm trying to uninstall and I'm getting the UserExit dialog defined inside the AdminUISequence with the property OnExit.
Any idea what am I missing?
Debugging: Managed code is relatively easy to debug (native code is actually even easier). Here are some pointers:
Debug C# Custom Actions (Advanced Installer)
Different debugging methods / aspects
Suggestions: I think you just have a broken reference to the dll export function - in other words an erroneous dll function name / reference:
<CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no"
BinaryKey="CustomActions" DllEntry="__ERRONEOUS FUNCTION REFERENCE__" />
Just check what the dll actually exports and match like this:
<CustomAction Id="CustomAction1" BinaryKey="CustomActions" DllEntry="CustomAction1"/>
As always the real McCoy is the check of the dll itself to see if you have the right function name (the below screen shot from this prior answer, recommended read).
This is a native code C++ dll:
This is a DTF-packaged managed code dll:
Notice that this is a native dll with the managed code stuff embedded. It yields a very different functions list, but you still have to find the function name in there that you refer to.
This is a straight-up managed code dll (no native wrapping):
And finally: this is the straight-up managed code DLL without being wrapped in a native dll shell.
Un-Uninstallable Setup: When a custom action crashes or fails during uninstallation, you will have problems getting rid of the installation (it just rolls-back and you are stuck with it installed). There are several fixes or workarounds.
The overall fix - in my view - is to not fail custom actions on uninstall, or at least condition them so you can force an uninstall by setting a property via the command line:
Set in MSI property table: SUPPRESSERROR = 0. Then - when needed - on the command line set:
msiexec.exe /x {PRODUCT-GUID} SUPPRESSERROR="1"
Inside the MSI you condition the uninstall custom action with:
REMOVE="ALL" AND SUPPRESSERROR="0"
Now the custom action will not run if SUPPRESSERROR is anything but 0.
There is an older answer with several further options: I screwed up, how can I uninstall my program? (courtesy of Wim Coenen, with me messing up his answer with more suggestions).
Boilerplate: For quick use, let me just dump a boilerplate ad-hoc custom action test project here. This assumes a C# managed code custom action project called "CustomAction1" in the same Visual Studio solution and a reference added to it in your WiX source - like you already have obviously (this is for later when we have all forgotten what the problem was and need to test again):
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="WiXCustomActionsTesting" Language="1033" Version="1.0.0.0"
Manufacturer="test" UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<UIRef Id="WixUI_Mondo" />
<Property Id="SUPPRESSERROR" Value="0" Secure="yes" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="WiXCustomActionsTesting" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<!--BEGIN CUSTOM ACTION SECTION-->
<Binary Id="CustomActions" SourceFile="$(var.CustomAction1.TargetDir)\$(var.CustomAction1.TargetName).CA.dll" />
<CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no" BinaryKey="CustomActions" DllEntry="CustomAction1" />
<InstallUISequence></InstallUISequence>
<InstallExecuteSequence>
<Custom Action='TestUninstallation' After='InstallInitialize'></Custom>
</InstallExecuteSequence>
<!--END CUSTOM ACTION SECTION-->
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WiXCustomActionsTesting" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component>
<File Source="C:\Projects\MySetup\MyApp.exe">
</File>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
Create WiX project
Copy paste the code, set a new Upgrade GUID
Create CustomAction project, default name
Add reference to custom action project from wix project
Add reference to WiXUIExtension.dll
Adjust path to file in component
Compile

WiX setup creating a Registry key doesn't work when also using CustomActions

I have issues understanding the order of operation of the WiX setup.
When trying to create a Registry key to add a menu entry to Windows Explorer context menu and simultaniously
using CustomActions the Registry key will not be added.
If I however only try to register the key, it works (any CustomAction code is commented out).
In my Product.wxs I have set elevated priviliges with
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated"/>.
In my <Feature> I have
<ComponentRef Id="RegistryEntries"/> referenced.
This is the code for creating the registry key
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="RegistryEntries" Guid="*">
<RegistryKey Root="HKCR"
Key="Excel.CSV\shell\Use MyConverter\command"
ForceCreateOnInstall="yes"
ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Value="[INSTALLLOCATION]$(var.SolutionName).exe %1"
KeyPath="yes"/>
</RegistryKey>
</Component>
<Directory Id="ProgramFilesFolder">
<Directory Id="HSZLG" Name="MyConverter">
<Directory Id="INSTALLLOCATION" Name="$(var.SolutionName)" />
</Directory>
</Directory>
<!--<Directory Id="ProgramMenuFolder">
<Directory Id="Shortcuts" Name="MyConverter" />
</Directory>-->
</Directory>
</Fragment>
Now Im also using the following Custom Actions:
<CustomAction Id="UnregisterImportFormat" BinaryKey="WixCustomAction" DllEntry="UnregisterImportDefinition" Execute="deferred" Impersonate="no" Return="check" />
<CustomAction Id="PropertiesForUnregisterImportFormat" Property="UnregisterImportFormat" Return="check"
Value="app=AB;key=10000P1000" />
And call them in the <InstallSequence> like this:
<InstallExecuteSequence>
<Custom Action="PropertiesForRegisterImportFormat" Before="RegisterImportFormat" />
<Custom Action="RegisterImportFormat" Before="InstallFinalize">(NOT Installed) OR REINSTALL</Custom>
<Custom Action="PropertiesForUnregisterImportFormat" Before="UnregisterImportFormat" />
<Custom Action="UnregisterImportFormat" Before="InstallFinalize">REMOVE</Custom>
</InstallExecuteSequence>
It'd be gladly appreciated if someone can point out what I am doing wrong here.
There are difficulties with (deferred) custom actions running without impersonation as well as the HKCR key because HKCR isn't an actual registry location - it's a merge of the interactive user and HKEY_LOCAL_MACHINE\Software\Classes. This goes into detail:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
and the custom action code is running with the system account (deferred, no impersonation) which is adding more confusion about which registry key you're creating. As that MSDN note says:
"To change the settings for the interactive user, store the changes under HKEY_CURRENT_USER\Software\Classes rather than HKEY_CLASSES_ROOT"
and I assume your code is attempting to use HKCR. Windows Installer is preferred for writing these registry entries because "it just works". Code running with the system account writing to HKCR is unreliable, so if you really must use code (and you shouldn't) then try HKEY_LOCAL_MACHINE\Software\Classes.

Add user before running custom action in Wix

We have an install script in Wix, which contains Fragments, components and some custom actions:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util='http://schemas.microsoft.com/wix/UtilExtension' >
<Product Id="*" Name="Installation" Language="1033" Version="1.0.0.0">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine">
</Package>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="cab1.cab" EmbedCab="yes" />
<Feature Id="ProductFeature" Title="MyInstallation" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentGroupRef Id="MyComponents" />
</Feature>
<util:Group Id="Users" Name="Users"/>
<CustomAction Id="InstallMyService"
Directory="INSTALLFOLDER"
ExeCommand="[INSTALLFOLDER]bin\my-service.bat install"
Execute="deferred"
Impersonate="no"
Return="check"/>
<CustomAction Id="SetEnvironmentVariable" BinaryKey="ActionLib" DllEntry="SetEnvironmentVariableForNewUser" />
<Binary Id='ActionLib' SourceFile='..\InstallerActionLibrary\bin\Release\InstallerActionLibrary.CA.dll' />
<CustomAction Id="StartMyService"
Directory="INSTALLFOLDER"
ExeCommand="[INSTALLFOLDER]bin\my-service.bat start"
Execute="deferred"
Impersonate="no"
Return="asyncWait"/>
<InstallExecuteSequence>
<Custom Action="InstallMyService" After="InstallFiles"/>
<Custom Action="SetEnvironmentVariable" After="InstallMyService"/>
<Custom Action="StartMyService" After="SetEnvironmentVariable"/>
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="CommonAppDataFolder">
<Directory Id="Company" Name="Company">
<Directory Id="App" Name="Product">
<Directory Id="INSTALLFOLDER" Name="Service" />
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="NewUser" Guid="{12345678-ABCD-1234-ABCD-987654321FED}">
<CreateFolder />
<util:User Id="CIUSER" CreateUser="yes" UpdateIfExists="no" Name="SERVICEUSER" PasswordNeverExpires="yes" Password="********">
<util:GroupRef Id="Users" />
</util:User>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
However, one of the Custom Actions, SetEnvironmentVariable, needs to be run after the user has been set up, in the fragment at the bottom of the file. And this does not happen. SetEnvironmentVariable fails because it cannot find the user.
The sequence, given in InstallExecuteSequence begins after InstallFiles has occurred. I have tried to find a more appropriate place to start the sequence, using the list given here. I have tried PublishProduct and the result is the same.
Is there any way to get the user added before the custom action runs?
The suggestion from #zett42 was a good one. However, it still did not solve the problem.
The solution was the incorrect use of Execute="deferred". The execution of all the custom actions should have been set as:
Execute="commit"
From the Wix Documentation:
commit
Indicates that the custom action will run after successful completion of the installation script (at the end of the installation).
Changed the Execute type to commit and it worked.
I have no direct answer, but one that should help you to figure it out by yourself:
Open the MSI package using a tool like Orca (included in Win SDK) or InstEd (my personal preference).
Navigate to the InstallExecuteSequence table.
Lookup the record of the WiX custom action that creates the user and copy the Action identifier of that record.
Use that identifier for the After attribute of the element <Custom Action="SetEnvironmentVariable"/>.
I agree with #zett42.
There are some wix standard actions which should be checked in msi editor,
if you need to know when exactly they are being called. We normally don`t get much documentation for such actions.
Check if your msi has SchedSecureObjects_x64 or SchedSecureObjects custom action in msi. Schedule SetEnvironmentVariable custom action after that action.

Wix: Feature Condition on Property set by Custom Action

In my WIX setup package I have a feature that contains merge module and must be installed conditionally. The condition should be evaluated using property set by custom action. Here's how this looks in my WXS:
<Directory Id="INSTALLLOCATION" Name="testSetup">
<Merge Id="mergeA" Language="1033" SourceFile="test.msm" DiskId="1" />
</Directory>
<InstallExecuteSequence>
<Custom Action="find" Before="CostInitialize">Not Installed</Custom>
</InstallExecuteSequence>
<CustomAction Id="find" Return="check" BinaryKey="script" VBScriptCall="findA" />
<Binary Id="script" SourceFile="script.vbs" />
Since level=0 disables the feature I've put NOT to install only if the path exists.
<Feature Id="productFeatA" Title="featA" Level="1">
<Condition Level="0"><![CDATA[NOT pathA]]></Condition>
<MergeRef Id="mergeA" />
</Feature>
And the simple test VBS script:
Function findA
Session.Property("pathA") = "test"
End Function
So using properties that are set via custom action I cannot get feature conditions to work. Any idea what I'm doing wrong here?
Your custom action is currently only scheduled to run in the InstallExecuteSequence. If your install runs through the InstallUISequence then the Feature will still get enabled. The InstallUISequence is unless you explicitly specify to run the install 'quietly'.
Fortunately, the fix is easy. Add the following as a peer of the InstallExecuteSequence:
<InstallUISequence>
<Custom Action="find" Before="CostInitialize">Not Installed</Custom>
</InstallUISequence>

Resources