I build a perMachine installer using WiX 3.6 to install a software I had not developed. Unfortunately the software creates some registry keys under HKCU during execution.
<The Windows Installer considers this user data and best practice is to not remove it. Either way, it's very difficult to try to remove it anyways since other user profiles are out of scope / context. It's theoretically possible to write a custom action to enumerate profiles and load registry hives but on some versions of Windows ( Vista ) that won't work due to restricted permissions granted to the windows installer service.
If you really, really must be able to remove custom action data on uninstall then take a look at:
Active Setup Explained
You are going to need to leave behind an program (exe for example ) by marking a component as permanent. Then you'll need a custom action to write a registry value during the uninstall (because Windows Installer doesn't support this).
The concept is during the install you lay down an EXE and during the uninstall you leave you. You then write to the ActiveSetup registry key telling it to run your EXE once for each subsequent user to logon to the machine. The EXE then deletes your registry values. Reboot (politely) if needed to unload the extensions from explorer.
But honestly, a better designed application wouldn't need all of this.
To overcome ICEs you should move Per-User registry to separate components and use some registry entry as keyPath for that component, i.e.:
<Component Id='PerUserRegistry' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPAth" KeyPath="yes" Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\[ProductCode]\PerUserRegistry" Name="[PackageCode]" Value="[ProductVersion]" Type="string" />
<!--Other Per-user registry goes here-->
</Component>
I completely agree with Christopher: It is common practice to leave per-user data on uninstall, but if removal is necessary, then Active Setup is the only real option.
First I propose you to remove them on Install or Re-Install instead of uninstall, you just need add RemoveRegirty entry and Active Setup, i.e. with this WiX code:
<Component Id='ActiveSetup' Guid='*'>
<RegistryValue Id="ActiveSetup00" Root="HKLM" KeyPath="yes" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Name="StubPath" Value="msiexec /fup [ProductCode] /qb-!" Type="string" />
<RegistryValue Id="ActiveSetup01" Root="HKLM" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Value="[ProductName] [ProductVerion] Configuration" Type="string" />
</Component>
<Component Id='PerUserRegistryCleanup' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPath" Root="HKCU" KeyPath="yes" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Name="StubPath" Value="msiexec /fup [ProductCode] /qb-!" Type="string" />
<RemoveRegistryKey Id='PerUserRegCleanup' Root='HKCU' Action='removeOnInstall' Key='Key\To\Be\Removed'/>
</Component>
Note: [PackageCode] use in ActiveSetup is very recommended, so with each new version (build) of MSI package you add separate entry (also see my final note). I used per-user active setup registry as key-path on purpose, so you don't run it for current user twice.
As for removing them after uninstall, Now, hopefully you need to remove entire key, and not just some values. In either case, I would create custom action to add Registry entry for Active Setup during uninstall (or if there are many such keys/values, create and deploy .CMD file with those and launch it on uninstall, before RemoveFiles action, to add all of them to registry).
Note: that I would strongly recommend adding deleting this registry during install, or you might end up removing per-user values when software is yet installed.
So here's WiX code for all of this:
<CustomAction Id="CA_UninstallRegistryCleanUp" Directory="SystemFolder" ExeCommand="REG.exe ADD "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp" /v StubPath /d "reg add ^"HKCU\Key\To\Be\Removed^" /va /f" /f" Return="ignore" />
<InstallExecuteSequence>
<Custom Action='CA_UninstallRegistryCleanUp' After='RemoveRegistryValues'>REMOVE~="ALL"</Custom>
</InstallExecuteSequence>
<Component Id='RegCleanup_Remover' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPAth" Root="HKLM" KeyPath="yes" Key="SOFTWARE\[Manufacturer]\[ProductName]\[ProductCode]\" Name="DummyKey" Value="[ProductVersion]" Type="string" />
<RemoveRegistryKey Id='RegCleanup_Remover' Root='HKLM' Action='removeOnInstall' Key='SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp'/>
</Component>
Final notes: There just two small issues with all this Active Setup stuff: be careful on Windows Terminal Servers; and once active setup was run for one user for current .MSI, it will not run again if you decide to reinstall same package, unless you change its PackageConde or raise version under ActiveSetup registry key. These are topics for another day, let me know if need them clarified.
And don't forget to add all of above Components to some Feature.