Wix uninstall not deleting registry value - wix

This is what I see from log during uninstall, action is null mean its not doing any action.
MSI (s) (00:D8) [14:54:39:091]: Component: Registry_Description; Installed: Local; Request: Absent; Action: Null; Client State: Local
RegistryValue Id="ExcelRegistry_Description"
Root="HKCU" Key="Software\Microsoft\Office\Excel\AddIns\ExcelAddIn"
Name="Description" Value="ExcelAddIn" Type="string" KeyPath="yes" />

I presume you are installing this registry key at install?
See below links, have you setup the right action?
Action="createAndRemoveOnUninstall">
Reference links:-
http://wixtoolset.org/documentation/manual/v3/howtos/files_and_registry/write_a_registry_entry.html
http://wixtoolset.org/documentation/manual/v3/xsd/wix/registrykey.html

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 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

Failed to create registry entry using WiX

The following code failed to create registry entry on Windows 7.
<Component Id='RegistryEntry1' Guid='1BECF977-A7A1-448E-8EC8-843A10E7F6D7' Directory='TARGETDIR'>
<RegistryKey Root='HKLM'
Key="SOFTWARE\Microsoft\Microsoft SDKs\Silverlight\v5.0\AssemblyFoldersEx\SimpleMvvmToolkit_2012.SL"
ForceCreateOnInstall="yes"
ForceDeleteOnUninstall="yes">
<RegistryValue Type="string"
Value="C:\Program Files\SimpleMvvmToolkit_2012\Binaries\Silverlight\v5.0\"
KeyPath="yes"/>
</RegistryKey>
</Component>
What could be the problem?
If the registry key wasn't created, more likely than not, the Component was not installed. Check a verbose log file from the install, for example:
msiexec /i path\to\your.msi /l*v install.txt
In that log file you will see lines like:
Component: RegistryEntry1; Installed: Absent; Request: Local; Action: Local
I expect the Action will be None or something not Local. Then look up in the log file to see why the Component was not installed.
PS: The ForceCreateOnInstall and ForceCreateOnUninstall are not necessary unless you expect random values to be created under that registry key that you must remove on uninstall.

How to prevent a Windows user from being removed and created during a patch

I have a project that uses the WiX extension WixUtilExtension to create a user for our Windows services. When I patch the installation (using an .msp), the custom actions RemoveUser and CreateUser are executed.
I don't want these WiX extension created custom actions to run during a patch.
I can add a condition directly to the custom action (ConfigureUsers) in the InstallExecuteSequence table of the MSI to prevent this, but I have not found a way to handle this in WiX.
Using WiX, how can I prevent RemoveUser and CreateUser from being executed during a patch?
<util:Group Id="LocalAdministrators" Name="Administrators"/>
<DirectoryRef Id="INSTALLLOCATION" DiskId="1">
<Component Id="CreateServiceAccountUser" Guid="{614550A7-C766-4B5D-9BF9-233D07EB3B69}">
<util:User Id="ServiceAccountUser"
CanNotChangePassword="yes"
CreateUser="yes"
Disabled="no"
FailIfExists="no"
LogonAsService="yes"
Name="TestUser"
Password="testuserpw"
PasswordExpired="no"
PasswordNeverExpires="yes"
RemoveOnUninstall="yes"
UpdateIfExists="yes">
<util:GroupRef Id="LocalAdministrators"/>
</util:User>
<RegistryKey Root="HKMU" Key="Software\AMT\WebBrix">
<RegistryValue Name="CreateServiceAccountUser"
Value="Common"
Type="string"
KeyPath="yes" />
</RegistryKey>
</Component>
</DirectoryRef>
You can do that in WiX:
<InstallExecuteSequence>
<Custom Action='ConfigureUsers'
After='InstallFinalize'>NOT Installed</Custom>
</InstallExecuteSequence>
Here are some more conditions
Action run only during Install
Condition: NOT Installed AND NOT PATCH
Action only runs during removal of MSI
Condition: REMOVE
Action runs during Install and repair
Condition: NOT REMOVE
Action runs during Install and remove
Condition: There must be no condition
Action calls EXE installed by MSI
Condition:NOT Installed AND NOT PATCH
Run on initial installation only:
NOT Installed
Run on initial install or when repair is selected.
NOT Installed OR MaintenanceMode="Modify"
Run when being uninstalled from command line or add / remove menu.
REMOVE~="All" OR MaintenanceMode="Remove"