So I'm stuck in wix hell. Come point and laugh at me.
I'm trying to create a wix installer that does some moderately complex things AND clean up after itself properly when uninstalled. This is apparently too much to hope for, as...
I can ether choose between executing my cleanup custom actions, or to remove the install folder, but not both.
The installer has five custom actions--two to bind an SSL cert to a port and add a url ACL for that port, two to remove these, and one to run the application after install.
If I do NOT execute the two custom actions that remove the cert binding and url ACL (by removing them or even if they fail), then the install folder is removed as expected. If I DO execute the two custom bindings, the install folder is NOT removed. Because I'm in wix hell.
The custom actions are pretty straight forward. Look, here they are.
<CustomAction Id="LaunchApplication"
BinaryKey="WixCA"
DllEntry="WixShellExec"
Impersonate="yes" />
<CustomAction Id="AddHttpsReservation"
Directory="INSTALLFOLDER"
ExeCommand="[SystemFolder]netsh http add urlacl url=https://127.0.0.1:9001/ sddl=D:(A;;GX;;;BU)"
Execute="deferred"
Impersonate="no"
Return="asyncWait" />
<CustomAction Id="AddHttpsBinding"
Directory="INSTALLFOLDER"
ExeCommand="[SystemFolder]netsh http add sslcert ipport=0.0.0.0:9001 certhash=S0M3C3RTHA5H appid={8feef448-1a4f-408f-b6d4-8a90300517ed}"
Execute="deferred"
Impersonate="no"
Return="asyncWait" />
<CustomAction Id="DeleteHttpsReservation"
Directory="INSTALLFOLDER"
ExeCommand="[SystemFolder]netsh http delete urlacl url=https://127.0.0.1:9001/"
Execute="deferred"
Impersonate="no"
Return="asyncWait" />
<CustomAction Id="DeleteHttpsBinding"
Directory="INSTALLFOLDER"
ExeCommand="[SystemFolder]netsh http delete sslcert ipport=0.0.0.0:9001"
Execute="deferred"
Impersonate="no"
Return="asyncWait" />
Here's my execute sequence. It might look a little strange to the experienced eye; I am definitely NOT experienced using wix (I've only built and maintained eight or so relatively complex installers, which would make me an enterprise architect if we were talking about C# applications, but because these are wix installers, I'm still considered a moron of the nth degree), but these (ALMOST) give me the cargo that I want, so that's why the bamboo planes:
<InstallExecuteSequence>
<Custom Action="LaunchApplication"
After="InstallFinalize">NOT REMOVE~="ALL"</Custom>
<Custom Action="AddHttpsBinding"
Before="InstallFinalize">Not Installed</Custom>
<Custom Action="AddHttpsReservation"
Before="InstallFinalize">Not Installed</Custom>
<Custom Action="DeleteHttpsReservation"
After="InstallInitialize">REMOVE~="ALL"</Custom>
<Custom Action="DeleteHttpsBinding"
After="InstallInitialize">REMOVE~="ALL"</Custom>
</InstallExecuteSequence>
(Side note, if I try to do the removes Before="InstallFinalize" or any other random place I've tried the damn things fail with an error code 1631, which I think is an elevation issue but who knows because wix hell)
Again, if I comment out the last two, the install folder gets deleted on uninstall, like I want (and like Microsoft wants, and will complain about if you try to get your application certified). If I try to pick another install execute sequence for scheduling, the custom actions fail (1631 mentioned before) but the directory gets removed. I've tried a few random ones and some logical ones as well (like RemoveFolders, wouldn't that be effing nice if it worked).
Something about successfully executing the removal actions (and something about wix hell) prevents that directory from being removed!
If I don't comment out the last two lines, everything gets uninstalled except the install folder, which throws an error in the log like to see it here it goes (slight language warning):
MSI (s) (0C:C0) [13:25:59:184]: Executing op: FileRemove(,FileName=readme.txt,,ComponentId={F3E98E05-E32A-5DC0-A551-64807B816AC2})
MSI (s) (0C:C0) [13:25:59:185]: Verifying accessibility of file: readme.txt
MSI (s) (0C:C0) [13:25:59:187]: Note: 1: 2318 2:
MSI (s) (0C:C0) [13:25:59:187]: Note: 1: 2327 2: 32 3: C:\Program Files (x86)\DealingWithThisWixBullshitInstaller\
MSI (s) (0C:C0) [13:25:59:188]: Note: 1: 2205 2: 3: Error
MSI (s) (0C:C0) [13:25:59:188]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 2911
DEBUG: Error 2911: Could not remove the folder C:\Program Files (x86)\DealingWithThisWixBullshitInstaller\.
MSI (s) (0C:C0) [13:25:59:190]: Note: 1: 2318 2:
MSI (s) (0C:C0) [13:25:59:191]: Note: 1: 2327 2: 32 3: C:\Program Files (x86)\DealingWithThisWixBullshitInstaller\
MSI (s) (0C:C0) [13:25:59:191]: Note: 1: 2205 2: 3: Error
MSI (s) (0C:C0) [13:25:59:191]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 2911
The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2911. The arguments are: C:\Program Files (x86)\DealingWithThisWixBullshitInstaller\, ,
DEBUG: Error 2911: Could not remove the folder C:\Program Files (x86)\DealingWithThisWixBullshitInstaller\.
None of the bamboo planes I've been constructing have resulted in neither glorious bountiful cargo nor a clean uninstall. I'm at a loss. Any ideas?
For the completists out there, here's the whole wxs from my MCVE (again, slight language warning):
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension">
<Product Id="*"
Name="DealingWithThisWixBullshitInstaller"
Language="1033"
Version="1.0.0.0"
Manufacturer="Derp"
UpgradeCode="1408102b-2ffd-41ff-ad57-6319b7fbfa58">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"
InstallPrivileges="elevated" />
<MajorUpgrade DowngradeErrorMessage="A newer version of this product is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature"
Title="DealingWithThisWixBullshitInstaller"
Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<Property Id="WixShellExecTarget"
Value="[#DealingWithThisWixBullshitExecutable]" />
<CustomAction Id="LaunchApplication"
BinaryKey="WixCA"
DllEntry="WixShellExec"
Impersonate="yes" />
<CustomAction Id="AddHttpsReservation"
Directory="INSTALLFOLDER"
ExeCommand="[SystemFolder]netsh http add urlacl url=https://127.0.0.1:9998/ sddl=D:(A;;GX;;;BU)"
Execute="deferred"
Impersonate="no"
Return="asyncWait" />
<CustomAction Id="AddHttpsBinding"
Directory="INSTALLFOLDER"
ExeCommand="[SystemFolder]netsh http add sslcert ipport=0.0.0.0:9998 certhash=E68AA1985440FDAD0BB07547BE2C9957F416709B appid={8feef448-1a4f-408f-b6d4-8a90300517ed}"
Execute="deferred"
Impersonate="no"
Return="asyncWait" />
<CustomAction Id="DeleteHttpsReservation"
Directory="INSTALLFOLDER"
ExeCommand="[SystemFolder]netsh http delete urlacl url=https://127.0.0.1:9998/"
Execute="deferred"
Impersonate="no"
Return="asyncWait" />
<CustomAction Id="DeleteHttpsBinding"
Directory="INSTALLFOLDER"
ExeCommand="[SystemFolder]netsh http delete sslcert ipport=0.0.0.0:9998"
Execute="deferred"
Impersonate="no"
Return="asyncWait" />
<InstallExecuteSequence>
<Custom Action="LaunchApplication"
After="InstallFinalize">NOT REMOVE~="ALL"</Custom>
<Custom Action="AddHttpsBinding"
Before="InstallFinalize">Not Installed</Custom>
<Custom Action="AddHttpsReservation"
Before="InstallFinalize">Not Installed</Custom>
<Custom Action="DeleteHttpsReservation"
After="InstallInitialize">REMOVE~="ALL"</Custom>
<Custom Action="DeleteHttpsBinding"
After="InstallInitialize">REMOVE~="ALL"</Custom>
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR"
Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER"
Name="DealingWithThisWixBullshitInstaller" />
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder"
Name="DealingWithThisWixBullshit"/>
</Directory>
</Directory>
</Fragment>
<Fragment>
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut"
Guid="*">
<Shortcut Id="ApplicationStartMenuShortcut"
Name="DealingWithThisWixBullshit"
Description="Dealing with this wix bullshit"
Target="[#DealingWithThisWixBullshitExecutable]"
WorkingDirectory="APPLICATIONROOTDIRECTORY"/>
<RemoveFolder Id="CleanUpShortCut"
Directory="ApplicationProgramsFolder"
On="uninstall"/>
<RegistryValue Root="HKCU"
Key="Software\Microsoft\DealingWithThisWixBullshit"
Name="installed"
Type="integer"
Value="1"
KeyPath="yes"/>
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<Binary Id="CACert"
SourceFile="muhfakecert.pfx"/>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents"
Directory="INSTALLFOLDER">
<Component Id="ProductComponent">
<File Id="DealingWithThisWixBullshitExecutable"
Vital="yes"
Source="$(var.DealingWithThisWixBullshit.TargetDir)DealingWithThisWixBullshit.exe"
Checksum="yes" >
</File>
<File Id="readme"
Source="$(var.DealingWithThisWixBullshit.TargetDir)readme.txt"
Checksum="yes" >
</File>
<iis:Certificate Id="CACert"
Name="CACert"
Overwrite="yes"
StoreLocation="localMachine"
StoreName="my"
PFXPassword="I HATE YOUR FACE AND I HOPE YOU DIE!"
BinaryKey="CACert"/>
</Component>
<ComponentRef Id="ApplicationShortcut"/>
</ComponentGroup>
</Fragment>
</Wix>