Remove folder confusion - wix

Using WiX, I'm replacing a application with a new version.
In the old version, there was a directory which is no longer needed in the new version.
So on install, this should do it:
<Component Id="killDir_" Guid="..." KeyPath="yes">
<RemoveFolder Id="killDir" On="both" />
</Component>
So far so good, this works fine.
But if the folder is already removed, the setup creates it again!
This happens also when using
<util:RemoveFolderEx .../>
I have tried a condition within the <Component> tag:
<Condition>OLD_STUFF_EXISTS</Condition>
along with a DirectorySearch in the Product:
<Property Id="OLD_STUFF_EXISTS">
<DirectorySearch Id='DirSearch' Path="OldDir" Depth='0'>
</DirectorySearch>
</Property>
But that doesn't seem to work.
In the MSI log file, the RemoveFolder seems to be executed:
MSI (s) (A0:4C) [13:44:45:742]: Doing action: RemoveFolders
MSI (s) (A0:4C) [13:44:45:742]: Note: 1: 2205 2: 3: ActionText
Action 13:44:45: RemoveFolders. Removing folders
Action start 13:44:45: RemoveFolders.
Action ended 13:44:45: RemoveFolders. Return value 1.
Some lines down, the istalled creates it again:
MSI (s) (A0:4C) [13:44:45:807]: Executing op: FolderCreate(Folder=C:\...\,Foreign=0,,)
Is there any way to tell the installer NOT to create it again?

Related

wixtoolset: Component condition is not evaluating as expected on changing MajorUpgrade schedule to afterInstallInitialize

MajorUpgrade element is scheduled after install finalize in our product's MSI:
<MajorUpgrade Schedule="afterInstallFinalize" AllowSameVersionUpgrades="yes" DowngradeErrorMessage="!(loc.NewerVersionInstalled)" IgnoreRemoveFailure="no"/>
There are some folders written by app at runtime that we want to keep on upgrade and only remove on uninstall initiated from Add/Remove programs. So we use this condition: (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL").
<DirectoryRef Id="TARGETDIR">
...
<Directory Id="LocalAppDataFolder"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Component Id="CreatePrivateMyAppFolder" Guid="FA1F4375-71DA-4E61-9A02-BE7FD2D4C87D">
<RegistryValue Root="HKCU" Key="Software\Company\Product" Name="PrivateFolderMyApp" Type="string" Value="[PrivateDataMyApp]" KeyPath="yes"/>
</Component>
<Component Id="RemoveLocalAppDataMyAppUninstall" Guid="*" Transitive="yes">
<Condition><![CDATA[(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")]]></Condition>
<RegistryValue Root="HKCU" Key="Software\Company\Product" Name="PrivateFolderMyApp" Type="string" Value="[PrivateDataMyApp]" KeyPath="yes"/>
<util:RemoveFolderEx On="uninstall" Property="PRIVATEMYAPPFOLDER"/>
</Component>
<Directory></Directory>
...
</Directory>
</DirectoryRef>
I need to change the MajorUpgrade schedule from afterInstallFinalize to afterInstallInitialize for some new requirements. I install version 1 with new schedule. Then install versions 2. However during uninstall sequence of version 2, folders written by runtime are being removed.
From logs, both UPGRADINGPRODUCTCODE and REMOVE properties are set for the uninstall part. Based on that the condition (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL") should evaluate to false for the component RemoveLocalAppDataMyAppUninstall.
MSI (s) (C4:58) [22:58:11:060]: Doing action: RemoveExistingProducts
Action 22:58:11: RemoveExistingProducts. Removing applications
Action start 22:58:11: RemoveExistingProducts.
RemoveExistingProducts: Application: {8F890AE0-BE0A-5ED9-B406-F7459B3390F9}, Command line: UPGRADINGPRODUCTCODE={70705091-36C8-5619-9E35-73E455CA17F7} CLIENTPROCESSID=4756 CLIENTUILEVEL=0 REMOVE=ALL
....
MSI (s) (C4:4C) [22:58:11:076]: Command Line: UPGRADINGPRODUCTCODE={70705091-36C8-5619-9E35-73E455CA17F7} CLIENTPROCESSID=4756 CLIENTUILEVEL=0 REMOVE=ALL
MSI (s) (C4:4C) [22:58:11:279]: Dir (target): Key: _PRIVATEMYAPPFOLDER_4 , Object: C:\Users\Windows_10\AppData\Local\MyApp\
MSI (s) (C4:4C) [22:58:11:279]: Dir (target): Key: _PRIVATEMYAPPFOLDER_3 , Object: C:\Users\Windows_10\AppData\Local\MyApp\1753de9b-15a7-49b1-8715-f93a967d12e5\
...
MSI (s) (C4:4C) [22:58:11:826]: Doing action: InstallValidate
MSI (s) (C4:4C) [22:58:11:826]: Component: RemoveLocalAppDataMyAppUninstall; Installed: Local; Request: Absent; Action: Absent
...
MSI (s) (C4:4C) [22:58:12:732]: Doing action: RemoveFiles
MSI (s) (C4:4C) [22:58:12:919]: Counted 6 foreign folders to be removed.
MSI (s) (C4:4C) [22:58:12:919]: Removing foreign folder: C:\Users\Windows_10\AppData\Local\MyApp\1753de9b-15a7-49b1-8715-f93a967d12e5\
MSI (s) (C4:4C) [22:58:12:919]: Removing foreign folder: C:\Users\Windows_10\AppData\Local\MyApp\
Any help in understanding why the condition is being applied during uninstall will be appreciated.
Component conditions only affect install and, with the transitive bit set, reinstall. Uninstall isn't affected. RemoveFolderEx in WiX v4 has a Condition that lets you do what you want to do.

How to change RemoveExistingProducts to after InstallFinalize when using WixUI_Advanced?

Here's my scenario:
Using Wix 3.6
Using the WixUI_Advanced dialog set (adds ability able to control individual features during install)
Setting NeverOverwrite="yes" for a web.config component (so that local changes post-install aren't lost)
However, the installer still seems to remove and re-install the web.config file during upgrade.
Best I can tell the WixUI_Advanced dialog set has something like the following configured:
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize"/>
</InstallExecuteSequence>
Here are logs snippets from the install:
MSI (s) (74:8C) [18:37:00:959]: Executing op: ActionStart(Name=InstallInitialize,,)
Action 18:37:00: InstallInitialize.
...
Action 18:37:00: ProcessComponents. Updating component registration
...
Action 18:37:00: UnpublishFeatures. Unpublishing Product Features
...
UnpublishFeatures: Feature: ProductFeature
...
UnpublishFeatures: Feature: AdditionalFeature
...
MSI (s) (74:8C) [18:37:00:967]: Executing op: ActionStart(Name=RemoveFiles,Description=Removing files,Template=File: [1], Directory: [9])
Action 18:37:00: RemoveFiles. Removing files
MSI (s) (74:8C) [18:37:00:967]: Executing op: ProgressTotal(Total=2,Type=1,ByteEquivalent=175000)
MSI (s) (74:8C) [18:37:00:967]: Executing op: SetTargetFolder(Folder=C:\Program Files (x86)\MyTestApp\WebApp\)
MSI (s) (74:8C) [18:37:00:967]: Executing op: FileRemove(,FileName=web.config,,ComponentId={B4A12A8F-56A3-4DD1-A0BA-B9C39EB305FD})
RemoveFiles: File: web.config, Directory: C:\Program Files (x86)\MyTestApp\WebApp\
MSI (s) (74:8C) [18:37:00:968]: Verifying accessibility of file: web.config
MSI (s) (74:8C) [18:37:00:969]: Note: 1: 2318 2:
MSI (s) (74:8C) [18:37:00:969]: Note: 1: 2318 2:
MSI (s) (74:8C) [18:37:00:969]: Executing op: FileRemove(,FileName=somefile.txt,,ComponentId={B835CEF5-1A84-4C37-8CB0-BE983BAF73F9})
RemoveFiles: File: somefile.txt, Directory: C:\Program Files (x86)\MyTestApp\WebApp\
MSI (s) (74:8C) [18:37:00:970]: Verifying accessibility of file: somefile.txt
MSI (s) (74:8C) [18:37:00:970]: Note: 1: 2318 2:
MSI (s) (74:8C) [18:37:00:970]: Note: 1: 2318 2:
MSI (s) (74:8C) [18:37:00:971]: Executing op: ActionStart(Name=PublishProduct,Description=Publishing product information,)
Action 18:37:00: PublishProduct. Publishing product information
...
Action 18:37:00: RollbackCleanup. Removing backup files
RollbackCleanup: File: C:\Config.Msi\7cd65c.rbf
RollbackCleanup: File: C:\Config.Msi\7cd65d.rbf
MSI (s) (74:8C) [18:37:00:980]: Note: 1: 2318 2:
MSI (s) (74:8C) [18:37:00:981]: Note: 1: 2318 2:
MSI (s) (74:8C) [18:37:00:981]: No System Restore sequence number for this installation.
MSI (s) (74:8C) [18:37:00:981]: Unlocking Server
MSI (s) (74:8C) [18:37:00:985]: PROPERTY CHANGE: Deleting UpdateStarted property. Its current value is '1'.
Action ended 18:37:00: InstallFinalize. Return value 1.
Action ended 18:37:00: INSTALL. Return value 1.
As you can see it removes the web.config file after InstallInitialize
When I try to change the wxs file, adding:
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallFinalize"/>
</InstallExecuteSequence>
I get:
error LGHT0091: Duplicate symbol 'WixAction:InstallExecuteSequence/RemoveExistingProducts' found. This typically means that an Id is duplicated. Check to make sure all your identifiers of a given type (File, Component, Feature) are unique.
Here is the Product.wxs file I'm using:
<?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="MyTestInstaller" Language="1033" Version="1.0.9.0" Manufacturer="Acme, Inc" UpgradeCode="6ca3779c-e8ce-42e8-bf81-3166bd96e585">
<Package Id="*" InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform="x64" InstallPrivileges="elevated" />
<Upgrade Id="6ca3779c-e8ce-42e8-bf81-3166bd96e585">
<UpgradeVersion Minimum="1.0.9.0" OnlyDetect="yes" Property="NEWERVERSIONDETECTED" />
<UpgradeVersion OnlyDetect="no" Minimum="0.0.0.0" IncludeMinimum="yes" Maximum="1.0.9.0" Property="OLDERVERSIONBEINGUPGRADED" IgnoreRemoveFailure="yes">
</UpgradeVersion>
</Upgrade>
<Condition Message="A later version of [ProductName] is already installed.">NOT NEWERVERSIONDETECTED</Condition>
<Media Id="1" Cabinet="myapp.cab" EmbedCab="yes" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Feature Id="ProductFeature" Title="MyTestInstaller" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<Feature Id="AdditionalFeature" Title="Additional Features" Level="10">
<ComponentGroupRef Id="AdditionalComponents"/>
</Feature>
<Property Id="ApplicationFolderName" Value="MyTestApp"/>
<!-- BEGIN: DISABLE THE Per User Install -->
<Property Id="WixAppFolder" Value="WixPerMachineFolder"/>
<WixVariable Id="WixUISupportPerUser" Value="0" />
<!-- END: DISABLE THE Per User Install -->
<UI>
<UIRef Id="WixUI_Advanced" />
</UI>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONFOLDER" Name="ICS">
<Directory Id="WebApp" Name="WebApp">
<Component Id="WEB.CONFIG" Guid="B4A12A8F-56A3-4DD1-A0BA-B9C39EB305FD" DiskId="1" NeverOverwrite="yes">
<File Id="WEB.CONFIG" Name="web.config" Source="web.config" KeyPath="yes"/>
</Component>
<Component Id="SOMEFILE" DiskId="1" Guid="B835CEF5-1A84-4C37-8CB0-BE983BAF73F9">
<File Id="SOMEFILE" Name="somefile.txt" Source="somefile.txt" KeyPath="yes"/>
<util:XmlConfig Id="WEBCFG_1" File="[WebApp]Web.config" Action="create" Node="element" Name="module" ElementPath="/configuration/autofac/modules" VerifyPath="/configuration/autofac/modules/module[\[]#type='ICS.Automation.JDE.Base.JDEModule, ICS.Automation.JDE.Base'[\]]" Sequence="10" On ="install" />
<util:XmlConfig Id="WEBCFG_2" ElementId="WEBCFG_1" File="[WebApp]Web.config" Name="type" Value="MyDll, MyDll" Sequence="11" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents">
<ComponentRef Id="WEB.CONFIG"/>
</ComponentGroup>
<ComponentGroup Id="AdditionalComponents">
<ComponentRef Id="SOMEFILE"/>
</ComponentGroup>
</Fragment>
</Wix>
How can I change the RemoveExistingProducts to come after InstallFinalize?
Ultimately, I just need this file to never be overwritten.
Thanks!
The MajorUpgrade tag is the preferred way to do the upgrade, and that will sequence RemoveExistingProducts (REP) wherever you specify - that should simplify some of this. There's no reason for the UI to move REP around.
The default for scheduling REP is after InstallValidate, which is basically a uninstall of the old product followed by an install of the upgrade, so it's not so much an update/overwrite of the config file as an uninstall/remove followed by a fresh install.
If the REP is scheduled afterInstallExecute then overwrite rules apply during the upgrade (because the upgrade "overwrites" the existing installed product before it's uninstalled). The web.config file just needs to have the same component id in both the old and new products, and if it has indeed been changed after it was installed then the overwrite rules should mean it won't be overwritten.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370531(v=vs.85).aspx
In other words just use the major upgrade element with afterInstallExecute, have the same component ids in both old and new resources (files etc) and the web.config file shouldn't be overwritten, and you don't need to set neveroverwrite.
In my opinion having REP afterInstallExecute is better than after InstallFinalize because the latter is outside the install transaction, so the upgrade install can succeed, then the REP after InstallFinalize can fail and roll back, leaving both products simultaneously installed. Having REP within the transaction results in a full rollback if the uninstall of the older product fails.

How to use RemoveFolderEx to recursively remove folder in LocalAppData on install AND uninstall

Here's what I have (based on what I've gleaned from several other Stack Overflow posts and elsewhere:
<Property Id="CACHEFOLDER">
<RegistrySearch Key="SOFTWARE\SIL\Transcelerator" Root="HKCU" Type="raw"
Id="CacheFolderRegSearch" Name="CachePath" />
</Property>
<Directory Id="TARGETDIR" Name="SourceDir
<!-- Transcelerator's cache folder in LocalAppData: -->
<!-- C:\Users\<current user>\AppData\Local\SIL\Transcelerator -->
<!-- This needs to be saved to a registry key so it can be cleaned up on uninstall and also purged when there is a new install in order to ensure that reparsing occurs. -->
<?define AppCacheFolder = "SIL\Transcelerator" ?>
<Component Id="CacheCleanup" Guid="{6A45D61D-EA73-4A8C-8941-B49A881ABB49}">
<RegistryValue Root="HKCU" Key="Software\SIL\Transcelerator" Name="CachePath"
Type="string" Value="[LocalAppData]$(var.AppCacheFolder)"
KeyPath="yes" />
<util:RemoveFolderEx On="both" Property="CACHEFOLDER"/>
</Component>
</Directory>
<Feature Id="MainApplication" Title="App Name" Level="1" Absent="disallow" Display="expand" AllowAdvertise="no" InstallDefault="local">
<ComponentRef Id="CacheCleanup" />
</Feature>
Note: Eventually, I'll want to make the MainApplication feature hidden, but for now it's comforting to see it.
Here are what I think are the relevant excerpts from the WIX log file:
AppSearch: Property: CACHEFOLDER, Signature: CacheFolderRegSearch
MSI (c) (38:F0) [18:25:39:116]: PROPERTY CHANGE: Adding CACHEFOLDER property. Its value is 'SIL\Transcelerator'.
Action ended 18:25:39: AppSearch. Return value 1.
...
MSI (c) (38:F0) [18:25:45:594]: Switching to server: PARATEXT7="C:\Program Files (x86)\Paratext 7\" PARATEXT7TEST="C:\Program Files (x86)\ParatextDir7Test\" PARATEXT8="C:\Program Files (x86)\Paratext 8\" PARATEXT8TEST="C:\Program Files (x86)\ParatextDir8Test\" PARATEXT75100ORGREATER="C:\Program Files (x86)\Paratext 7\Paratext.exe" CACHEFOLDER="SIL\Transcelerator" TARGETDIR="C:\" INSTALLDIR7="C:\Program Files (x86)\Paratext 7\plugins\Transcelerator\" INSTALLDIR7TEST="C:\Program Files (x86)\ParatextDir7Test\plugins\Transcelerator\" INSTALLDIR8="C:\Program Files (x86)\Paratext 8\plugins\Transcelerator\" INSTALLDIR8TEST="C:\Program Files (x86)\ParatextDir8Test\plugins\Transcelerator\" PLUGINDIR7="C:\Program Files (x86)\Paratext 7\plugins\" PLUGINDIR7TEST="C:\Program Files (x86)\ParatextDir7Test\plugins\" PLUGINDIR8="C:\Program Files (x86)\Paratext 8\plugins\" PLUGINDIR8TEST="C:\Program Files (x86)\ParatextDir8Test\plugins\" CURRENTDIRECTORY="C:\Projects\Transcelerator" CLIENTUILEVEL="0" CLIENTPROCESSID="17976" SOURCEDIR="C:\Projects\Transcelerator\output\installer\" ACTION="INSTALL" EXE
...
MSI (s) (E4:44) [18:25:46:006]: PROPERTY CHANGE: Adding CACHEFOLDER property. Its value is 'SIL\Transcelerator'.
...
Action 18:25:46: WixRemoveFoldersEx.
Action start 18:25:46: WixRemoveFoldersEx.
MSI (s) (E4:00) [18:25:46:041]: Invoking remote custom action. DLL: C:\Windows\Installer\MSI6019.tmp, Entrypoint: WixRemoveFoldersEx
MSI (s) (E4:78) [18:25:46:042]: Generating random cookie.
MSI (s) (E4:78) [18:25:46:044]: Created Custom Action Server with PID 18712 (0x4918).
MSI (s) (E4:54) [18:25:46:067]: Running as a service.
MSI (s) (E4:54) [18:25:46:069]: Hello, I'm your 32bit Impersonated custom action server.
WixRemoveFoldersEx: Recursing path: SIL\Transcelerator\ for row: wrfA9D8B049E87ACFF02034C5FFCFB64E42.
WixRemoveFoldersEx: Search path not found: SIL\Transcelerator*
Action ended 18:25:46: WixRemoveFoldersEx. Return value 1.
...
MSI (s) (E4:44) [18:25:46:267]: Executing op: ComponentRegister(ComponentId={6A45D61D-EA73-4A8C-8941-B49A881ABB49},KeyPath=01:\Software\SIL\Transcelerator\CachePath,State=3,,Disk=1,SharedDllRefCount=0,BinaryType=0)
1: {97A212AC-E01E-486A-A220-AF9BBBC79E87} 2: {6A45D61D-EA73-4A8C-8941-B49A881ABB49} 3: 01:\Software\SIL\Transcelerator\CachePath
...
MSI (s) (E4:44) [18:25:46:597]: Executing op: RegOpenKey(Root=-2147483647,Key=Software\SIL\Transcelerator,,BinaryType=0,,)
MSI (s) (E4:44) [18:25:46:597]: Executing op: RegAddValue(Name=CachePath,Value=SIL\Transcelerator,)
WriteRegistryValues: Key: \Software\SIL\Transcelerator, Name: CachePath, Value: SIL\Transcelerator
...
Property(S): CACHEFOLDER = SIL\Transcelerator
Nothing relevant seems to be getting added to the registry. (At one point, it seems it was adding something withe correct GUID to tell it to do an uninstall action, but now I can't figure out what I changed to make that go away.) And none of files or subfolders in C:\Users\bogle\AppData\Local\SIL\Transcelerator are getting removed either on install or uninstall. I also tried changing from On="both" to On="Uninstall" to see if I could get that to work, but no dice.
I ended up using a custom action because it turns out that what I really needed to do was clear the cached files for any/all users, not just the current user. This was especially true because the installer always runs under elevated privileges, so the current user quite typically would not be the one I actually care about. I will point out that the original problem remains unsolved, so if anyone can figure out the problem and post an alternate answer that might help someone else, that could be useful.
The name of the directory property is LocalAppDataFolder, not LocalAppData. That's not defined so it's an empty string and the path RemoveFolderEx is given isn't valid (hence the Search path not found: SIL\Transcelerator error).

WiX Toolset - Is there a way to hide Util:XmlFile calls from the log?

Even though I hide the WiX property that contains a password and the ExecXmlFile property...
<Property Id="MyApp_MyServer_constr" Hidden="yes" />
<Property Id="ExecXmlFile" Hidden="yes" />
<DirectoryRef Id='MYAPPDIR'>
<Component Id='UpdateMyAppMyServerConnectionString' Guid='MY-GUID' Win64="yes">
<CreateFolder />
<util:XmlFile Id='UpdateMyAppMyServerConnectionString'
Action="setValue"
ElementPath="[MyServer_elementpath]"
File="[MYAPPDIR]MyApp.exe.config"
Value="[MyApp_MyServer_constr]" />
</Component>
</DirectoryRef>
...password details are exposed in the MSI install log file.
MSI (s) (F0:7C) [20:27:56:613]: Executing op: ActionStart(Name=ExecXmlFile,,)
Action 20:27:56: ExecXmlFile.
MSI (s) (F0:7C) [20:27:56:613]: Executing op: CustomActionSchedule(Action=ExecXmlFile,ActionType=3073,Source=BinaryData,Target=ExecXmlFile,CustomActionData=20C:\Program Files\MyCompany\MyInstallerName\MyApp\MyApp.exe.config30//configuration/connectionStrings/add[#name='MyServer']/#connectionStringUser ID=sa;Password=wysiwyg;Initial Catalog=MyDatabase;Data Source=MACHINE-NAME;Application Name=MyShortAppName)
I've done a considerable amount of checking online, but there does seem to be a WiX way of hiding this information from an MSI log without doctoring things using Orca after creating an MSI.
I found this WiX bug http://wixtoolset.org/issues/3859/, but it seems that not allowing hiding of ExecXmlFile CustomAction calls was by design.
Alternately, is there another WiX way to accomplish what I need that doesn't expose password details in the log file?
Thanks

Attach Registry Property with Edit Control in WiX

I'm looking to update the value of registry using a Edit Control in WiX installation process.
I have no problem in using Edit Control which I'm using as follows -
<Property Id="WIXUI_USERLIST" Value="Demo;" Secure="yes"/>
<Control Id="UsersList" Type="Edit" X="105" Y="192" Width="180" Height="18" Property="WIXUI_USERLIST" Indirect="no" />
This works fine to take user input and push the value in registry using WIXUI_USERLIST.
Problem start when I introduce following code to read the registry to display existing value in Edit control in a property and attach it to WIXUI_USERLIST as
<Property Id="USERLIST" Secure="yes">
<RegistrySearch Id="UserList"
Root="HKLM"
Key="[APPLICATIONHIVE]"
Name="UserList"
Type="raw"
Win64="yes" />
</Property>
<SetProperty Id="WIXUI_USERLIST" Value="[USERLIST]" After="AppSearch">USERLIST</SetProperty>
Looking at the log suggest the value correctly passed to the INSTALL phase but gets overwritten by USERLIST.
Action 14:37:22: INSTALL.
Action start 14:37:22: INSTALL.
MSI (s) (78:44) [14:37:22:770]: Running ExecuteSequence
MSI (s) (78:44) [14:37:22:770]: Doing action: FindRelatedProducts
MSI (s) (78:44) [14:37:22:770]: Note: 1: 2205 2: 3: ActionText
Action 14:37:22: FindRelatedProducts. Searching for related applications
Action start 14:37:22: FindRelatedProducts.
MSI (s) (78:44) [14:37:22:772]: Skipping FindRelatedProducts action: already done on client side
Action ended 14:37:22: FindRelatedProducts. Return value 0.
MSI (s) (78:44) [14:37:22:772]: Doing action: AppSearch
MSI (s) (78:44) [14:37:22:772]: Note: 1: 2205 2: 3: ActionText
Action 14:37:22: AppSearch. Searching for installed applications
Action start 14:37:22: AppSearch.
MSI (s) (78:44) [14:37:22:774]: Skipping AppSearch action: already done on client side
Action ended 14:37:22: AppSearch. Return value 0.
MSI (s) (78:44) [14:37:22:774]: Doing action: WIXUI_USERLIST
MSI (s) (78:44) [14:37:22:774]: Note: 1: 2205 2: 3: ActionText
Action 14:37:22: WIXUI_USERLIST.
Action start 14:37:22: WIXUI_USERLIST
MSI (s) (78:44) [14:37:22:775]: PROPERTY CHANGE: Modifying WIXUI_USERLIST property. Its current value is 'Gurinder;TestUser'. Its new value: 'Gurinder'.
Action ended 14:37:22: SetWIXUI_PORTSERVERADD. Return value 1..
In log "Gurinder" is stored in registry and edit during install to "Gurinder;TestUser"
There are a few ways to solve this problem but I believe the following is the probably the most efficient. It just requires a few tweaks to what you've done already.
First, I'd put the default values in USERLIST so that WIXUI_USERLIST can always be set. Second, need the WIXUI_USERLIST to be set only once in the UI or Execute sequence. The SetProperty element doesn't expose this ability but we can get to it using the CustomAction element. Getting the action to run only once in the sequences is the magic.
The resulting code for setting the properties would go a little like this:
<Property Id="USERLIST" Value="Demo;" Secure="yes">
<RegistrySearch Id="UserList"
Root="HKLM"
Key="[APPLICATIONHIVE]"
Name="UserList"
Type="raw"
Win64="yes" />
</Property>
<!-- replaces SetProperty but adds the ability to run only in the first sequence -->
<CustomAction Id='SetWIXUI_USERLIST' Property='WIXUI_USERLIST' Value='[USERLIST]'
Execute='firstSequence'>
<InstallUISequence>
<Custom Action='SetWIXUI_USERLIST' After='AppSearch' />
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action='SetWIXUI_USERLIST' After='AppSearch' />
</InstallExecuteSequence>
Update: Additionally, I went and double checked my memory against the MSI SDK. The AppSearch action is only executed once. That means I believe you could probably remove all the WIXUI_USERLIST and custom actions and stuff and just use USERLIST everywhere. So an even simpler solution is to remove all of this and replace all instances of your WIXUI_USERLIST with USERLIST. :)