Wix: condition on property not working - wix

I have a util:RemoveFolderEx element that I only want to run when the program is being uninstalled. I put it inside its own component then set up a condition on a property as to whether it should be included.
Can anyone explain to me why the following doesn't work?
<Property Id='UNINSTALLMODE' Value="FALSE"></Property>
<DirectoryRef Id="DATADIR">
<Component Id="C.RemoveDataFolder" Guid="myguid" KeyPath="yes">
<util:RemoveFolderEx On="uninstall" Property="DATADIR" ></util:RemoveFolderEx>
<Condition>(UNINSTALLMODE="TRUE")</Condition>
</Component>
</DirectoryRef>
<CustomAction Id="CA.SetUninstallMode" Property="UNINSTALLMODE" Value="TRUE" />
<InstallExecuteSequence>
<Custom Action="CA.SetUninstallMode" Before="WixRemoveFoldersEx" >(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")</Custom>
</InstallExecuteSequence>
I've checked the logs and the custom action correctly sets UNINSTALLMODE to "TRUE" when uninstalling the software. On install and reinstall it is "FALSE". I've tried the custom action to be scheduled Before="WixRemoveFoldersEx" and Before="CostInitialise" which are relevant to the RemoveFoldersEx.
Any help is much appreciated, this is driving me nuts! Neil
EDIT: I updated the wix to this
<Property Id='P.INSTALLMODE' Value='0'></Property>
<Property Id='P.UNINSTALLMODE' Value='0'></Property>
<DirectoryRef Id="DATADIR">
<Component Id="C.RemoveDataFolder" Guid="myguid" KeyPath="yes">
<util:RemoveFolderEx On="uninstall" Property="DATADIR" ></util:RemoveFolderEx>
<Condition>(P.INSTALLMODE = 1) OR (P.UNINSTALLMODE = 1)</Condition>
</Component>
</DirectoryRef>
<CustomAction Id="CA.SetInstallModeToTrue" Property="P.INSTALLMODE" Value='1' />
<CustomAction Id="CA.SetUninstallModeToTrue" Property="P.UNINSTALLMODE" Value='1' />
<InstallExecuteSequence>
<RemoveExistingProducts Before="InstallInitialize" />
<Custom Action="CA.SetInstallModeToTrue" Before="ValidateProductID" >(NOT UPGRADINGPRODUCTCODE) AND (NOT PREVIOUSVERSIONSINSTALLED)</Custom>
<Custom Action="CA.SetUninstallModeToTrue" Before="ValidateProductID" >(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")</Custom>
</InstallExecuteSequence>
The custom actions run immediately after the DATADIR value is read from the registry and before the CostInitialize.
Here is what happens in the following situations
Install -> condition is met and the component is installed
Reinstall -> condition is not met but the component is still uninstalled then reinstalled
Uninstall -> condition is met and the component is uninstalled
All I can take from this is that the condition is only applicable for the installation procedure and once a component is installed it is not possible to impose a condition on it for being removed.
EDIT2: Finally got this working by using a property for the removefolderex which is set by a custom action. Seems simple now.
<Property Id='P.REMOVEDATAFOLDER' Secure='yes' />
<DirectoryRef Id="DATADIR">
<Component Id="C.RemoveDataFolder" Guid="myguid" KeyPath="yes">
<util:RemoveFolderEx On="uninstall" Property="P.REMOVEDATAFOLDER" />
</Component>
</DirectoryRef>
<CustomAction Id="CA.SetDataFolder" Property="P.REMOVEDATAFOLDER" Value='[DATADIR]' />
<InstallExecuteSequence>
<Custom Action="CA.SetDataFolder" Before="ValidateProductID" >(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")</Custom>
</InstallExecuteSequence>

The condition of the component, which holds the RemoveFolderEx element, is False on install. This means the component is not installed. If it's not installed, it obviously won't be uninstalled, either. Hence, even if the condition-driving property is True on uninstall, the CA won't run because the component it depends upon was not installed.

Related

How to prevent json modification while wix msi upgrading

I am new to wix msi .I am using Wix to create msi for my window service .While installing msi, a json file will be created in installation folder with application details(using .net core). This file will be modified (recreating) while upgrading msi .I want to prevent json being modified on each msi upgrade.
I have tried couple of methods. But didn't get desired result.
1.Using custom action-
<Property Id="C_TEMP" Value="C:\Temp" />
<Property Id="ROBOCOPY_EXE">robocopy.exe</Property>
<CustomAction Id="CopyToTemp" Property="ROBOCOPY_EXE" Return="ignore" ExeCommand='"[INSTALLDIR]\Configuration" "[C_TEMP]\ServerSettings" AgentDetails.json' />
<CustomAction Id="CopyFromTemp" Property="ROBOCOPY_EXE" Return="ignore" ExeCommand='"[C_TEMP]\ServerSettings" "[INSTALLDIR]\Configuration" AgentDetails.json /MOVE /IS' />
<InstallExecuteSequence>
<Custom Action="CopyToTemp" Before="InstallInitialize">Installed AND (NOT REMOVE="ALL" OR UPGRADINGPRODUCTCODE)</Custom>
</InstallExecuteSequence>
using component
<Component Id="myconfig" NeverOverwrite="yes" Permanent="yes" >
<File Id="AgentDetails.json" Name="AgentDetails.json" KeyPath="yes" Source="$(var.BasePath)\AgentDetails.json" />
</Component>

WIX Updater doesn't using setup params from previous version

I have the wix project installer.
I want to use the update new version of my product.
It works fine, but still shows me all dialogs and I need to enter params.(such as install path, user credential and other).
How can I skip all dialogs and using all of these params from older (prev) installer version.
<Product Id="*" Name="$(var.ProductName) $(var.ProductVersion)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform="x64" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." AllowSameVersionUpgrades="yes" />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="COMPANY.Product.Installers.Server" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentGroupRef Id="ServerInstallerFiles" />
</Feature>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" ></Property>
<UIRef Id="WixUI_MinimalCustom"/>
<InstallExecuteSequence>
<Custom Action="DoAfterInstallJobParams" Before="DoAfterInstallJob">Not Installed or REINSTALL</Custom>
<Custom Action="DoAfterInstallJob" After="InstallFiles">Not Installed or REINSTALL</Custom>
<Custom Action="DoBeforeUnstallJob" After="InstallInitialize">REMOVE="ALL"</Custom>
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLFOLDER" Name="COMPANY" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<Property Id="DoBeforeUninstallJob" Value="[INSTALLFOLDER]" />
<Binary Id="CustomActionBinary" SourceFile="$(var.SolutionDir)Output\Installers\Actions\COMPANY.Product.Installers.Server.Actions.CA.dll" />
<CustomAction Id="DoAfterInstallJob" BinaryKey="CustomActionBinary" DllEntry="AfterInstall" Execute="deferred" Return="check" Impersonate="no" />
<CustomAction Id="DoAfterInstallJobParams" Property="DoAfterInstallJob" Value="HOSTING_URL=[HOSTING_URL];DB_CONNECTION=[DB_CONNECTION];INSTALLPATH=[INSTALLFOLDER];LOGIN=[LOGIN];PASSWORD=[PASSWORD]" />
<CustomAction Id="DoBeforeUnstallJob" BinaryKey="CustomActionBinary" DllEntry="BeforeUninstall" Execute="deferred" Return="check" Impersonate="no" />
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<ComponentRef Id="cmpServerHost"/>
</ComponentGroup>
</Fragment>
<Fragment>
<DirectoryRef Id="INSTALLFOLDER">
<Directory Id="ServerHost" Name="ServerHost">
<Component Win64="yes" Id="cmpServerHost" Guid="a4a81104-1e30-463d-87e1-e8a79b4c6829">
<File Id="ServerLog4netConfig" Source="$(var.SolutionDir)..\Logging\log4net.config" />
<RegistryValue Root="HKLM" Key="Software\[Manufacturer]\$(var.ProductName)" Type="string" Value="[INSTALLFOLDER]" KeyPath="yes" Name="COMPANYInstallPath"/>
<File Id="AppVersion" Source="$(var.SolutionDir)Output\Installers\Actions\COMPANY.Product.Installers.Server.Actions.CA.dll" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
Windows Installer does not persist properties. You have to do it yourself. Here is an example.
http://robmensching.com/blog/posts/2010/5/2/the-wix-toolsets-remember-property-pattern/
Remember Properties: Persisting properties allows you to read back the settings from the first version.
Dialog Control & Order: In order to skip dialogs you need to detect whether a major upgrade is taking place, if you use major
upgrades (which you do based on that source file), and then control
the dialog flow accordingly using conditioning and property values. This requires quite a bit of work and
testing. I would avoid it if you can.
Easy Mode: Just disabling (write protect) or hiding the dialogs fields that contain settings written in the first setup might be
preferable (rather than changing the dialog sequence). You can use conditions and conditioning for both purposes.
Maintenance GUI: For minor upgrades, repair and uninstall the dialog set will be different from the original installation. You will get a "maintenance dialog set" presented rather than the "installation dialog set".
Major Upgrade: A pecularity occurs when you install upgrades via Windows Installer's major upgrade mechanism. Because of how this works technically you get the installation dialog set for the new version as well. This is because it is technically a fresh install of that new product code. The fact that the older version gets uninstalled as part of the process is besides the point. You are not installing a new minor version, you are uninstalling and reinstalling effectively.
WIX_UPGRADE_DETECTED: There is a property that is set in a standard WiX package. It is WIX_UPGRADE_DETECTED. It can be used to detect when a major upgrade is taking place and hence used in conditions to adjust the dialog order of a major upgrade installation. Here are more details on this property, along with description of UPGRADINGPRODUCTCODE - which is another property that is set in the setup being uninstalled (not in the new one being installed).
Here is a quick list of different ways to change WiX GUI.
Wix, custom dialog when previous version exists (customize dialogs when previous version exists).
Ran out of time. Persisting this, will update later.
Some Links:
Removing Default dialogs from MSI

WIX Uninstall Custom Action Error Code 2753

I'm having problems with a WIX CustomAction that I'd like to run when a user uninstalls an application.
Here's my XML
http://schemas.microsoft.com/wix/2006/wi'>
<Package Description='pak' InstallerVersion='200' Compressed='yes' />
<Media Id='1' Cabinet='setup.cab' EmbedCab='yes' />
<Property Id='ARPSYSTEMCOMPONENT'>1</Property>
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id="TempFolder">
<Directory Id="INSTALLLOCATION" Name="~_tmpdir">
<Component Id='MyComponent' DiskId='1' Guid=''>
<File Id="File0" Name="Runtime.exe" Source="Runtime.exe" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id='InstallFeature' Title='Install Feature' Level='1'>
<ComponentRef Id='MyComponent' />
</Feature>
<CustomAction Id="RunInstall" Return="ignore" Execute="deferred" FileKey="File0" ExeCommand="Runtime.exe" HideTarget="no" Impersonate="no" />
<CustomAction Id="RunUninstall" Return="ignore" Execute="deferred" FileKey="File0" ExeCommand="Runtime.exe" HideTarget="no" Impersonate="no" />
<InstallExecuteSequence>
<Custom Action="RunInstall" Before="InstallFinalize">NOT REMOVE~="ALL"</Custom>
<Custom Action="RunUninstall" Before="InstallFinalize">REMOVE~="ALL"</Custom>
</InstallExecuteSequence>
The Runtime.exe launches as expected when installing the application but when I uninstall I get an error "The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2753".
Looking at the event viewer sheds a little more light on the problem, it contains the following "The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2753. The arguments are: File0, , ".
So, it seems like it can't find Runtime.exe but I'm not sure why. The file is bundled into the MSI and it runs on install but I can't work out why it doesn't run on uninstall.
Many thanks
You should sequence the uninstall custom action earlier. "Before InstallFinalize" is very late, and almost certainly results in attempting to run the program after RemoveFiles has deleted it, hence the error. Look at the InstallExecuteSequence in your MSI file and see where RemoveFiles is relative to your CA and InstallFinalize. You may need to be before StopServices and other actions that remove registry values, depending on how much of the installed product your code needs. Or run it from the Binary table (beware of dependencies) if it really needs to be literally just before the uninstall completes.

WiX Installer InstallPrivelges="elevated" not working

When I run my installer I get the following issue.
I'm doing some custom actions which require to access the registry and I can only think that its because the WiX configuration doesn't make it request admin priveleges. I've looked at some posts on SO and tried to use.
InstallPriveleges="elevated"
within the package element however this does not make the installer have the admin shield nor request it therefore still producing the error.
Extra information about test project.
The name of my application is :WindowsFormsApplication33, the name of the custom action project is CustomAction1 and name of the Setup project is SetupProject1.
This is my current wix xml file.
<Package InstallerVersion="200" Compressed="yes" InstallPrivileges="elevated" InstallScope="perUser" />
<Binary Id="CustomAction1.CA.dll" SourceFile ="..\CustomAction1\bin\$(var.Configuration)\CustomAction1.CA.dll" />
<CustomAction Id="disableTaskManager"
Return="check"
Execute="immediate"
BinaryKey="CustomAction1.CA.dll"
DllEntry="disableTaskManager" />
<CustomAction Id="enableTaskManager"
Return="check"
Execute="immediate"
BinaryKey="CustomAction1.CA.dll"
DllEntry="enableTaskManager" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="SetupProject1" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<InstallExecuteSequence>
<Custom Action="disableTaskManager" Before="InstallFinalize" />
<Custom Action="enableTaskManager" After="InstallInitialize"><![CDATA[(NOT UPGRADINGPRODUCTCODE)]]></Custom>
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="Form Test Application" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Guid="{EDA315F6-A115-4348-8607-981C252EA317}">
<File Source="$(var.WindowsFormsApplication33.TargetPath)" KeyPath ="yes" />
</Component>
<Component Guid="{E3182F61-F563-4C13-82B5-8CC39D9DB380}">
<File Source="$(var.CustomAction1.TargetPath)" KeyPath ="yes" />
</Component>
<Component Guid="{E4AF325E-B244-47F5-855A-5B40DBC425D2}">
<File Source="..\WindowsFormsApplication33\bin\Release\WindowsFormsApplication33.exe.config" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
Update : changing the InstallScope value from perUser to "perMachine" does make a UAC prompt however the DLL error still exists..
Your custom action is immediate, that means it will not run with elevation. It must be deferred to run with elevation. It's got nothing to do with WiX particularly, it's just that immediate custom actions run as the user but limited.
I struggled to get rid of the dll error however an alternative I found was to NOT use Custom Action and use the XML in the wix file to create the registry and then delete the key when uninstalling via the use of :
ForceDeleteOnUninstall="yes"
You have to use this in the
Example :
<!-- Register windows autostart registry -->
<Component Id="RegistryEntries" Guid="45C7AC46-1101-4301-83E1-D24392283A60">
<RegistryValue Type="string"
Name="FooStartup"
Value="[#FooMainApp]"
Root="HKLM"
Key="Software\Microsoft\Windows\CurrentVersion\Run"
Action="write"/>
</Component>
As found on : Registry change upon installing application C#
I really hope this helps someone new to WiX as it did to me.
Use these three attributes inside custom action tag.
<CustomAction ....
Execute="deferred"
Impersonate="no"
Return="ignore" />
These fields will make the custom action to run with admin priveleges.

WIX Order of execution with Custom Action

I have a wix project that installs a web site, a couple of SQL Server databases and configures users etc.
Part of the install creates a database for the ASP.NET membership system using a Custom Action to execute aspnet_regsql.exe.
Another part of the installation then needs to execute a SQL script to create an initial user. The problem is that the script component is getting executed before the Custom Action has happened, so the references to membership tables and stored procedures in the script are invalid and the install fails.
This is part of my install file:
<Feature Id="Complete" Title="Darzi Web" Level="1" Display="expand" ConfigurableDirectory="INSTALLDIR">
<ComponentGroupRef Id="SiteIISConfig"/>
<ComponentGroupRef Id="SQLConfig" />
<ComponentGroupRef Id="InstallFiles" />
<ComponentRef Id="WebConfigChanges" />
<ComponentGroupRef Id="SQLBootstrap" />
</Feature>
<InstallExecuteSequence>
<Custom Action='RegSql' After='InstallFiles'/>
</InstallExecuteSequence>
I need a way to tell the installer to make sure that "SQLBootstrap" happens after "RegSql".
Any help would be gratefully received.
EDIT
This is the section that runs the Bootstrap SQL:
<Fragment>
<DirectoryRef Id="INSTALLDIR">
<Component Id="SqlBoostrapComponent" Guid="CAAA1447-446F-4C1B-9239-812ABA5AF0FF" KeyPath="yes">
<sql:SqlScript SqlDb='DarziAspNetDbDatabase' Id='Bootstrap' BinaryKey='Bootstrap' ExecuteOnInstall='yes' Sequence='1' />
</Component>
</DirectoryRef>
<Binary Id='Bootstrap' SourceFile='Bootstrap.sql' />
<ComponentGroup Id="SQLBootstrap">
<ComponentRef Id="SqlBoostrapComponent" />
</ComponentGroup>
</Fragment>
Assuming the Sql scripts you run are using the inbuilt sql actions You need to schedule the InstallSqlData action after your RegSql action:
<Custom Action="InstallSqlData" After="RegSql" />