WiX: Forcefully launch uninstall previous using CustomAction - wix

I'm writing a new major upgrade of our product.
In my installer I start by finding configuration settings of the previous version, then I'd like to uninstall the previous version.
I have found several guides telling me how one should make a MSI suitable for such upgrades.
However, the previous was not an MSI.
It was not according to best practices.
It does, however, in registry HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall{GUID} specify an UninstallString.
Using a RegistrySearch I can easy find the command below, which I store in UNINSTALL_CMD.
RunDll32 C:\PROGRA~1\COMMON~1\INSTAL~1\PROFES~1\RunTime\10\01\Intel32\Ctor.dll,LaunchSetup
"C:\Program Files\InstallShield Installation Information\{GUID}\setup.exe"
-l0x9 -removeonly 4:
I cannot get the hang of the CustomAction needed to perform the actual uninstall.
<CustomAction Id="ca.UninstPrev" Property="UNINSTALL_CMD" ExeCommand="" />
The MSI logs says:
Info 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: ca.UninstallPrevious, location: RunDll32 C:\PROGRA~1\COMMON~1\INSTAL~1\PROFES~1\RunTime\10\01\Intel32\Ctor.dll,LaunchSetup "C:\Program Files\InstallShield Installation Information{GUID}\setup.exe" -l0x9 -removeonly, command:
Anyone seeing what I am doing wrong here?
Regards
Leif

I did application repackaging for a couple years at Continental Airlines where I did SMS pushes to an 18,000 seat forest. I frequently had a legacy application in the wild that was not installed using MSI that I needed to get redeployed using MSI and once that was done I supported major upgrades going forward.
These previously deployed apps typically had very broken and misbehaved uninstallers. Instead of calling these, I would use SMS to query the forest to get all the deployed versions. I would then deploy those old packages to a integration lab and work out what it was each installer did to the machine and write my own aggregated "forced cleanup" custom action that was capable of wiping the various versions of the application off the machine.
I executed this custom action prior CostInitialize so that when the new MSI did it's costing it wouldn't be influenced by the crap that was no longer on the machine. This worked for me because I pushed packages as System and I didn't have to worry about elevation issues. If you want to be fully UAC compliant you would want to run this custom code from a prereq package and either have your users run it manually or wire it into a bootstrapper to run prior to your MSI.

After a good nights sleep I found my error.
If you really read http://wix.sourceforge.net/manual-wix3/wix_xsd_customaction.htm the answer was there.
I was trying to make a type 50 custom action, launch an executable already installed on system.
Property specifies the full path to an executable to launch
ExeCommand specifies the command line arguments for this executable above.
And my fault was that I did place the full exe+command line in the Property field.
/L

Related

Why would a WiX installation create two entries in HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\

I'm trying to uninstall an older version of our product which was installed using a WiX-built installer and after uninstalling it silently:
msiexec /x{GUID}
the program still appears in Control Panel. I've opened a separate item to
explore that mystery, but another curious issue has popped up. I noticed that after running the install for this program, two entries (GUIDs) are added to HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall. One with the product GUID and one that I have no idea where it comes from. I've searched through the .msi and it's not in there. Both are created each time I install, both are removed if I uninstall from the Control Panel and both are left in the registry if I uninstall from the command line. So have a look
Anyone have any ideas what's going on here?
Embedded Setup.exe: In essence it looks like you are installing an MSI that also installs an embedded non-MSI setup.exe via a custom action as part of its own installation sequence. Or, there is a setup.exe launcher that kicks off the MSI and the legacy setup in sequence. Result: two entries in Add / Remove Programs.
Uninstall: It is obvious, but to get rid of the second entry you must run its uninstall sequence - in addition to the uninstall of the MSI. Non-MSI setups are less reliable when it comes to uninstall than MSI packages. The implicitly available uninstall for all MSI packages with reliable silent running is one of the core benefits of MSI: MSI Core Benefits (among other topics).
Uninstall Commands: Try running the silent uninstall string, I guess that is what you have done?
Run commands elevated! With admin rights!
REM Uninstall MSI
msiexec.exe /x {PRODUCT-GUID} /L*v C:\MySetup.log /QN
REM Uninstall legacy setup.exe
"%SystemDrive%\ProgramData\Package Cache\{c5f0cb3e-1de3-4971-843a-abb981ed670c}\MDRSetup.exe" /uninstall /quiet
Silent Running: To run legacy setups silently you sometimes have to record a "response file" to record all settings in the GUI and pass to the uninstall process. I have some previous answers on this. You also need to run with admin rights:
Create MSI from extracted setup files
Regarding silent installation using Setup.exe generated using Installshield 2013 (.issuite) project file
How to run an installation in /silent mode with adjusted settings
Application Repackaging: What is the name of the software you are installing? MDRSetup.exe, is that Max Data Recovery 1.9? Probably not. Getting rid of legacy software can be challenging. You can always try to re-package it as an MSI if you have the tools to do so, or maybe you have a team in your company to do so (all large companies tend to). Not all legacy setups can be repackaged. There could be constructs that are impossible to capture, such as certain drivers, generated and unique keys per machine etc...
Links:
Create MSI from extracted setup files
How can I use powershell to run through an installer?
Wix - How to run/install application without UI
Capturing all changes during an application install on Windows

Windows per-machine install requires reference to original installer when second user runs application

I'm working on an MSI installer written in Wix. The installer works in both per-user, and per-machine contexts.
In a per-machine installation, everything goes smoothly; the product is installed and configured for the initial user. Upon switching to a test user, the application appears in the start menu correctly. Running it for the first time, a msiexec process starts with the message that the app is being configured. However, if the original .msi has been deleted, this process fails.
The failing setup action gives the following message in its log:
Error 1706. An installation package for the product myProduct cannot be found. Try the installation again using a valid copy of the installation package 'myInstaller.msi'.
=== Logging stopped: 3/16/2017 11:15:52 ===
I understand from reading a blog post by Rob Mensching (Lead of Wix) that it probably isn't possible to just edit the source list to point towards the windows cached .msi, a point backed up by another article I've found. Is that correct?
Is there a way to stop this entire action of calling the msi on first run by users from happening? Caching the msi or keeping the original is not ideal, I'd like to use the .msi in a custom bootstrapper that involves deleting the msi once installation is complete.
Microsoft recommends you keep the original MSI available, Rule 31:
https://blogs.msdn.microsoft.com/windows_installer_team/2006/05/24/tao-of-the-windows-installer-part-3/
and I won't repeat what it says about repair/resiliency, but you cannot guarantee the source MSI won't be needed sometime.
You're probably getting this "repair" because there is some resource (a file most likely) that is being installed to a user-profile location. When another user logs on and uses the application that file is missing, so potentially the application is broken. For example a file installed to User's Application Data needs to be available for all users of the system, not just the user that installed it.
So keeping the MSI might not be ideal but is strongly recommended, and in your case of product use by multiple users it's even more likely to required. There should be an Application Event log entry under MsiInstaller that says something about the missing resource.

I screwed up, how can I uninstall my program?

My Wix installer worked installing my program, but it's broken for uninstallation. A file is removed too early, and it's needed further down the line. The uninstaller fails and reverts its changes.
This means I can't remove the package from my machine, and hence can't install any further builds of my installer (a considerable inconvenience). How can I force removal of the package?
Update, Stein Åsmul: Injecting this newer list of cleanup approaches.
Find your package in C:\Windows\Installer, where Windows keeps copies of installed MSI packages. The names are generated randomly, so you'll have to look at the creation dates of the files.
Open the MSI file with Orca. (Unfortunately there is no simple download for the orca installer. You can get it by installing the "MSI Tools" of the Windows 10 SDK, and then searching for orca.msi in C:\Program Files (x86)\Windows Kits.)
Delete the offending custom action from the CustomAction table
Now you should be able to uninstall the package.
UPDATE: You can find the actual cache MSI file using Powershell. That was for one package, you can also get for all packages (scroll down to first screenshot).
This command usually works for me:
msiexec /fv installer.msi
It somewhat recaches the installer, so you can try again with a corrected one.
One time this command didn't work and I had to use Microsoft FixIt. It solved the problem (quite a shock for me).
Depending on the exact reason of the behavior you described, you might have at least a couple of options.
If the reason of the failure is a custom action which runs on uninstall, and this custom action is conditioned with some properties you can influence upon, you can try to pass the desired value via the command line:
msiexec /x {YOUR-PRODUCTCODE-HERE} RUNMYACTION=false
In this sample RUNMYACTION is a Windows Installer property which participates in a custom action condition, and if you pass false as its value, the action won't run.
Otherwise, you can fix the logic (or just disable the custom action explicitly) and build the new MSI package. Then upload it to that target machine, and run like this:
msiexec /i YourPackage.msi REINSTALL=ALL REINSTALLMODE=vomus
Here YourPackage.msi is a new fixed package, REINSTALL=ALL instructs the msiexec to re-install the product using this new package, and REINSTALLMODE=vomus (the v part of it) will re-cache the MSI package and you'll be able to remove it the normal way afterwards.
A side note: you should test your installation on a virtual machine in order not to risk your real one.
FYI: In Windows 8.1 the installers have been moved here: C:\ProgramData\Package Cache\
If you are really desperate and all solutions above don't work try
msizap.exe
This will erase all that your installer put on a machine
LITTLE WARNING
Don't run msizap without knowing what options you want to run it with (for a list of options run msizap /? first).
I used this little tool also from Microsoft
https://support.microsoft.com/en-us/help/17588/fix-problems-that-block-programs-from-being-installed-or-removed
Basically this tool can be used to "repair issues including corrupted registry keys that block you from installing or removing programs"
What it fixes:
Corrupted registry keys on 64-bit operating systems
Corrupted registry keys that control the update data
Problems that prevent new programs from being installed
Problems that prevent existing programs from being completely uninstalled or updated
Problems that block you from uninstalling a program through Add or Remove Programs (or Programs and Features) in Control Panel
It can be used for:
Windows 7
Windows 8
Windows 8.1
Windows 10
I usually just look for <Your Installer's Name>.msi or <Your Installer's Company Name> in the registry and delete some of the uninstall keys from some of the Products under the Windows installer trees and everything usually works fine and dandy afterwards, although this WOULD leave some stuff lying around like cached installers and possibly tons of other registry keys for each file installed, etc. but its ALWAYS worked for me when developing installers because honestly, who cares if one MSI is left over and cached somewhere? You're using the machine for development anyways, right?

Automatic updating and upgrade management for Windows Installer XML (WiX)

I have been using InstallShield LE in Visual Studio 2010, but it is heavily limited and sometimes buggy. I looked at paid InstallShield versions, but these also have too many limitations for that price tag.
So I decided to switch to WiX. I have had some experience with it some years ago. It was pretty easy to build a simple installer using SharpDevelop with WiX tools.
Now I am trying to collect solutions and tools for WiX. Basically, I need to get the following functionality (requested by my client):
when I launch the installer, it should check a text file on the server and see if a newer version is available. If it's the case, then the installer should be able to download the updated installer package and launch it (are there any downloader utilities in WiX?)
solving dependencies. Major dependency of my app is .NET 4 (which itself depends on Windows Installer 3). The installer should offer the user to download and install them automatically
logging the installation process, also collecting the log file of the dependencies' installation process. I don't want the user to hunt various .log files in case .NET4 or WindowsInstaller3 installation fails. All the information should be collected in one place and if something fails, I should show the user a custom popup dialog with an option to save the complete install log file and send it to me
installer should be able to detect if there is a newer version of my app already installed, and show a meaningful customized error message before it exits
installer should be able to detect if there is an older version of my app already installed. and offer the user to exit installation or uninstall the previous version and install the new version. BTW, there are no minor component upgrades planned, I prefer to reinstall everything fresh (I guess, this is a major upgrade in the terms of WindowsInstaller). Installshield LE failed on me for this, it just showed an error box with the message about another product, but did not offer to uninstall it
in case of an upgrade, installer should be able to detect if some of application components are in use (running application processes) and show a custom error message and not just some cryptic "Installation failed"
I have read that it may be a bit painful to manage upgrades even if I keep my UpgradeCode intact, because this code is stored in the Windows Registry in a compressed way and also if the user renames the downloaded file, it might get detected as a completely new product by WindowsInstaller ... or maybe this is only the case with WindowsInstaller .msi files and WiX has some trick to avoid this issue?
About update downloading - I need this functionality also in my application itself. I am not sure how to implement it efficiently, so I can reuse the same update downloader code/utility in both WiX installer and in my app.
Is it possible to satisfy all these requirements using currently existing WiX tools, or maybe I'll need to code some components from scratch?
WiX is definitely the way to go in my opinion.
when I launch the installer, it should check a text file on the server and see if a newer version is available. If it's the case,
then the installer should be able to download the updated installer
package and launch it (are there any downloader utilities in WiX?)
In my opinion, this type of functionality is best handled by the application. However you can implement such functionality in a custom bootstrapper. The latest development of WiX includes a bootstrapper engine Burn that allows you to write your own custom bootstrapper on top of it.
solving dependencies. Major dependency of my app is .NET 4 (which itself depends on Windows Installer 3). The installer should offer
the user to download and install them automatically
You can use the standard WiX bootstrapper to install .NET as a prereq. Or if you create your own custom managed bootstrapper application, you can install .NET a prereq to your bootstrapper as in this example
logging the installation process, also collecting the log file of the dependencies' installation process. I don't want the user to
hunt various .log files in case .NET4 or WindowsInstaller3
installation fails. All the information should be collected in one
place and if something fails, I should show the user a custom popup
dialog with an option to save the complete install log file and send
it to me
Using the two bootstrapping methods above, when you launch your msi you can specify parameters for logging. In my own custom managed bootstrapper I created a button to open the log files created during installation.
installer should be able to detect if there is a newer version of my app already installed, and show a meaningful customized error
message before it exits
You can do this using launch conditions
installer should be able to detect if there is an older version of my app already installed. and offer the user to exit installation or
uninstall the previous version and install the new version. BTW,
there are no minor component upgrades planned, I prefer to reinstall
everything fresh (I guess, this is a major upgrade in the terms of
WindowsInstaller). Installshield LE failed on me for this, it just
showed an error box with the message about another product, but did
not offer to uninstall it
In my experience this major upgrades are the least complicated
approach.
in case of an upgrade, installer should be able to detect if some of
application components are in use (running application processes) and
show a custom error message and not just some cryptic "Installation
failed"
I think WiX/Windows Installer are generally good at handling these
scenarios and automatically notifying the user that
files/applications need shutdown without you having to author
anything extra in your installer.
All that said, you may want to look into creating your own custom managed bootstrapper using WiX and Burn. That is not trivial however. The best place to go is to download the source code to the WiX Weekly Releases and checkout the project src\Setup\WixBA. It is the custom BA that they wrote to install WiX. There isn't much documentation out there yet because WiX 3.6 is not released (although it is pretty stable). However you don't have to create your own BA to make a solid WiX installer that can handle upgrades and logging.

Wix / MSI : Unable to uninstall

I've developed a Wix installer for an internal project however entirely by accident I've found that I'm unable to uninstall the installer on my development machine as I get the following error message:
The feature you are trying to use is on a network resource that is unavailable
with a dialog pointing to the path of the .msi that I installed from feature from. (The .msi is there, however is has been rebuilt and so has changed since I installed it)
I'm concerned by this dialog as I had believed that Windows Installer kept track of installed .MSI files, however this dialog seems to suggest that I can break my uninstaller by deleting, moving or changing the installer.
Is this the case?
What do I need to do to make sure that I don't break my uninstaller in this way? (Do we need to keep copies of all versions of the installer ever installed on a machine?)
The easiest way to get out of this situation is to do a recache/reinstall. Build a new version of your MSI that isn't "broken" (in whatever way it is broken, in this case, it might not really be broken at all, you just need a new source). Then you use a command line like:
msiexec /fv path\to\your.msi /l*v i.txt
That will copy your.msi over the MSI that is cached and do a repair. Then you'll be in a better place.
One of the first painful lessons of writing installs is to never run your install on your own box. Certainly not until it reaches a point of maturity and has gone through several QA cycles. This is what we have integration labs and virtual machines for. (There is a saying about things you shouldn't do in your own back yard.)
That said, normally an MSI uninstall doesn't require the MSI but there are situations where it could be required. For example if one was to call the ResolveSource action during an uninstall, MSI would then look for the .MSI.
Now there are several ways out of this pickle:
Take an MSI you do have and edit it with ORCA to match to file name, UpgradeCode, ProductCode and PackageCode of the MSI that you installed. You should be able to get all of this information from looking at the stripped cached MSI that exists in %WINDIR%\Installer. CD to that directory and do a findstr -i -m SOMESTRING *.msi where SOMESTRING is something unique like your ProductName property. Once you know the name of the cached MSI, open it in Orca to get the required attributes. Then put these attributes in a copy of the MSI you have available and try to do an uninstall. No, it's not the exact MSI that you installed but usually it's close enough.
or
Use the front end windows installer cleanup utility (if you still have it) and/or the backend MSIZAP utility to wipe all knowledge of the application from MSI and Add/RemovePrograms. Note, this doesn't actually uninstall the program so you'll have to also write a script or otherwise manually uninstall all traces of the program.
or
Reimage your workstation
If you know exactly what is wrong (which is often the case during development), I prefer to open the MSI file that Windows will use for uninstallation and edit it directly with a tool like Orca to fix or remove the part that causes the failure.
For example:
Locate the MSI file in %WINDIR%\Installer. The MSI should be the last edited MSI file in that folder right after you did the failed uninstallation.
Open the msi file with Orca.
Remove the failing part - for example the InstallExecuteSequence action that fails which is atypical scenario.
Save the msi and close Orca to release the lock on the msi file.
1 - Have you experimented with "run from source" during installation?
This is an option in the feature tree which allows you to run some files from their installation source. This is generally combined with an admin image on the network. See image below. I haven't tried it, but I assume this could cause: "The feature you are trying to use is on a network resource that is unavailable" if the network is down and you are trying to uninstall. Just a theory, there are other ways this could happen.
2 - Are you running script custom actions? If so, do you extract to the tmp folder or run from installed files or the binary table? If so, is the custom action conditioned to run only on install?
3 - Are you perhaps running an EXE custom action that is pointing to an installed file? If so this file may be unreachable on the network.
4 - Are any of your userprofile folders redirected to a network share?
5 - Are you installing anything directly to a folder on the network?
There are plenty of other possibilities.