WiX - Renaming files/folders in next versions of setup - wix

We have a product that we install using WiX, and we have done some re-branding, and I would like to change some things in installation paths and file names.
So, when I make a new version of our installation, the folder with old name remains in Start menu, for example. Also, if I rename a file, the old versions are not deleted, either.
I would like to know what would be the best way of installing files with new names over previous versions of installation.

It sounds like you're doing a major upgrade with a late scheduling of RemoveExistingProducts. When you do that, you have to strictly follow the component rules. My blog post on upgrades covers ways of avoiding that, such as by using an early scheduling of RemoveExistingProducts.

Related

Existing Uninstaller Broken During Upgrade - Patch MSI?

I wrote a custom action to help during upgrade of my product (from 1.0 to 1.1). Now I need to upgrade from 1.1 to 1.2 but the existing uninstaller is failing during upgrade. I got the execution conditions of my custom action wrong. (Lesson learned, always test upgrading to the next version before deploying).
Right now it seems my best option is to modify the InstallExecuteSequence table in the existing .msi to disable the failing custom actions. I'll have to create another custom action to browse the registry, locate the existing .msi in C:\
Windows\Installer, patch it, and then continue with the upgrade. This sounds like a terrible, error prone solution, but I'm really at a loss. This was supposed to be an automatic, silent upgrade pushed down from a remote cloud.
Another option would be to write a batch script to uninstall the existing product, then execute the new installer.
Any advice?
EDIT This question is already answered here: I screwed up, how can I uninstall my program?
The supported way to do this is a patch (by which I mean an MSP file, not coding to alter the cached MSI file). That's by far the most straightforward way to get out of the situation. After that, do the upgrade. Using WiX you could probably put the MSP and the upgrade in a bundle.
In any case, you wouldn't do your proposed change with another MSI. A small executable can do what you propose, and:
MsiGetProductInfo (ProductCode, …, INSTALLPROPERTY_LOCALPACKAGE)
is how you find the cached MSI.
Conditioning: What condition did you set on the failing custom action? And more importantly, what is the new condition you are intending to use? It sounds like regular uninstall works but major upgrade fails? The typical problem is that uninstall fails altogether, and then the usual solution is a minor upgrade which I will quickly describe.
Minor Upgrade: Normally what I use is a minor upgrade to fix whatever is wrong in the current install's (un)installation sequence(s). A minor upgrade does not uninstall the existing installation, it upgrades it "in-place", and the uninstall sequence is hence never called and thusly you avoid all its errors from manifesting themselves. There is no need to browse to the cached MSI file and hack it manually if you do things correctly in your minor upgrade. The updating of the cached MSI will happen auto-magically by the Windows Installer Engine provided you install with the correct minor upgrade command line.
Future Upgrades: A minor upgrade will generally always work if you make it simple enough, but the problem is usually applying it since it often targets only a single, previous version. When you get to the next release and if you then use a major upgrade, you will see the error in your original MSI manifest itself on uninstall if you are upgrading an installation that never had the minor upgrade applied - in other words it is still the oldest version of your installation. This is generally solved by a setup.exe launcher which will install the minor upgrade if need be. The bad news is that you need to keep that update in every future release - if you want to avoid any upgrade errors. Or in a corporate environment you would use the distribution system to check what is already on the box and install accordingly. If your manual uninstall works correctly (but major upgrade uninstall fails), all you should need to do is to push an uninstall command line to msiexec.exe as the first command to run via your setup.exe I think. Then there is no need to include any minor upgrade binaries in your setup.exe launcher.
Detect & Abort?: Michael Urman's answer here explains how it might be difficult to make sure that the minor upgrade is present on the box before applying the next version of your software:
InstallShield fails because of a bad uninstall. He suggests making your package better at detecting whether a new upgrade can be safely applied.
Some Links:
how to omit a component when we try to build .msi using wix (on how patching is just a distribution mechanism for MSI upgrades that must already be working)
Is there any possible way to perform upgrade when Product codes for old and new versions are same? (on minor upgrades and their technical limitations)
Here is a hack that I got working, but based on the answers above it looks like it's not the preferred way.
[CustomAction]
public static ActionResult Patch11Installer(Session session)
{
string localPackage = NativeMethods.GetMsiInstallSource("{MY-PRODUCT-CODE}");
if (String.IsNullOrEmpty(localPackage))
{
session.Log("Failed to locate the local package");
return ActionResult.Failure;
}
session.Log($"Found local package at {localPackage}");
using (Database database = new Database(localPackage, DatabaseOpenMode.Direct))
{
foreach (string action in new string[] { LIST OF CUSTOM ACTION NAMES })
{
session.Log($"Modifying condition for action {action}");
database.Execute($"UPDATE InstallExecuteSequence SET Condition='WIX_UPGRADE_DETECTED' WHERE Action='{action}'");
}
database.Commit();
}
return ActionResult.Success;
}
The custom action calls MsiGetProductInfo to query for the v1.1 MSI using the v1.1 product code which I obtained from installer log files. It then opens the MSI database and modifies the Condition property of the InstallExecuteSequence table for the list of custom actions that are failing. It changes the Condition from "UPGRADINGPRODUCTCODE OR WIX_UPGRADE_DETECTED" to "WIX_UPGRADE_DETECTED". UPGRADINGPRODUCTCODE is the property that's causing the uninstall to fail during a major upgrade as this property is passed to the uninstaller and contains the new product code; the product code for v1.2 in my case. Here is the custom action definition in my installer file.
<CustomAction Id="Patch11Installer" Return="check" Impersonate="yes" Execute="immediate" BinaryKey="MyUpgradeCustomActions" DllEntry="Patch11Installer" />
I'll look into implementing a minor upgrade as suggested in other answers. I just thought I would leave this solution here.

WiX Upgrade with custom versioning

I got a problem. I want to upgrade my app during installation process, but I run into problem with versioning. I use version number in format e.g. 5.5.789.0, some new version has version number in format 5.5.12.1. I know that installer only works with first three numbers from version so MajorUpgrade is not suitable for me. New version would not be installed in this case. Is there a way in which I can check versions in some custom action and plan upgrade from there? I cannot change the versioning as app building goes through some automatic post-processes that also works only with first three numbers and it is not possible to change that behavior.
Thanks for suggestions.
EDIT:
I am using WiX#.
It's not obvious to me why you can't use the WiX majorupgrade element. The settings would be AllowDowngrades=yes, maybe AllowSameVersionUpgrades=yes.
Using Schedule=afterInstallValidate is (as the docs say) removes the old product entirely before installing the new upgrade.

Registry issue when upgrading

The old version of the setup was created with InstallScope="PerMachine".
The new version is intended to have InstallScope="PerUser"; it also needs to use the same registry keys as the old version creates.
The problem is that whatever values are stored under these registry keys during the upgrade will be overwritten at the end with the initial values stored by the old version. Even deleting these keys manually before the installation will make them reappear (with the wrong values) after the installation process.
I have tried creating a custom action and specifically delete these keys, but the result is the same.
How can I ensure that the old version does not interfere with the installation process of the new version allowing to delete the old Registry Keys and re-create them?
What I found to be working:
Performing a REPAIR immediately after installing the new version will yield the correct results!
Uninstalling the old version manually before installing the new one will not remove the keys, but will allow to overwrite them with the correct values.
You should define what kind of upgrade you are doing, and if it's a major upgrade then where is it sequenced in your major upgrade element, although...
Probably the main issue is that cross context major upgrades aren't supported by Windows Installer, so if you are doing a major upgrade you will end up with both products installed. That's not an upgrade, that's most likely just a collision. So assuming that you want only one of them to be installed at the end of all this, you will need to uninstall the older per-machine installation and then install the per-user. As to why the uninstall of the per-machine product doesn't remove the registry keys, there are many possible reasons, such as they were created by the app not the MSI, or the component was marked permanent, or the component has another client product on the system - a log of the uninstall might show what's going on.
I have to add this as an answer, too long as a comment. I will "evolve" it once you provide more information:
Why do you want to switch to per-user installation? In the MSI world this is not an ideal way to deploy. An application is usable per-user even if installed per machine. With a per-machine install you simply add the ability to write shared settings that should not be overridden by a user. And your application is easier to upgrade, uninstall, patch and manage overall.
Here are a few more links to explain some of the problems with per-user setups. They are real, I am only trying to warn people what problems they are most likely going to face (almost certainly going to face):
Having an issue with WIX upgrade
Understanding “Per-User” or “Per-Machine” context for application Setup packages
Are you deploying HKCU or HKLM keys? I would not recommend writing any HKCU values from your setup, they should be written by the application itself. A setup is for writing to HKLM and other places that require "elevated rights". It should never be used to write user preferences. There will be interference when you do upgrades (as you have experienced).
Where is the registry data you speak of stored? In a single MSI component or several? Is there anything else in that component that still needs to be installed without the registry keys? If you can, please add your source WiX file so we can see for sure.
I am sure that we can make all these problems go away if you follow our advice precisely. You are facing a very common MSI problem.
Let me attempt a tentative answer without having all the information:
Remove all HKCU registry information from your setup (if you can).
Update your application to write these HKCU values itself, and ideally write to a brand new location in the registry instead of the old one. For example HKCU\Software\MyCompany\MyApp\5 instead of HKCU\Software\MyCompany\MyApp. This "decouples" your old and new state, and you got room to maneuver and clean up things.
Making your application write the HKCU keys is not a hack, but the right thing to do. It will make your application much more robust and generally easier to QA for yourself and your team. You can "wipe the slate clean" during testing and start over without a reinstall - in order to focus on application testing.
Put any remaining HKLM settings in a single WiX component and set a good key path that will never be modified or deleted by the user or any other process. For example: HKLM\Software\MyCompany\MyApp\5\MyAppHKLMKeyPath = 1
If you discover that you have to override a value for each user (in other words change something for every user in HKCU), you can do this with this approach which combines what the setup does with the application itself: http://forum.installsite.net/index.php?showtopic=21552 (if this is important, please read the whole, linked thread).

Installing multiple instances of an Application with Wix Toolset

I simply need to install multiple instances of my application saving them in different folders, with no shortcut on desktop.
In other words, when the App is already installed in a Folder, if I double-click the .msi file once again, the installer shouldn’t ask me if I want repair or remove my App, but it simply should permit to install it in a new folder.
How can I solve this problem?
I used to work with this kind of installations before, and I would agree with #Nikolay - it is rather an exception, than the rule when it comes to Windows Installer based installations. Component rules are often tricky to follow, and multiple instances aspect adds some complexity on top. So, think twice before you go this road.
Being complex, it is still possible. Years ago I published the article of how to start authoring multiple instance installations with WiX 3.6. Note that this version of WiX simplifies it significantly. It's not a short read, so here is a quick digest:
You won't be able to achieve the "install each new instance with double-clicking MSI file" behavior. You have to have a bootstrapper - something that passes correct command line parameters to msiexec.exe.
Don't try to support unlimited number of instances - try sticking with reasonably big number. Do you imagine someone installing your app 10 times on a machine? 50? 100? Make a sane choice - this will be the number of your <Instance/> elements.
Although you only have to decorate non-file data components with MultiInstance attribute, I don't think it will break if you add it to all of your components.
Although I explained the patching of multiple instances in that post, I would only use it in production if I had no other choice.
What you are asking for is not normal in Windows. Normally, each program (product) is installed only once. I.e. each installation package has it's ID (called "ProductID"). If that ID already registered in the system as installed, the system will not allow you to install the second product with the same ProductID, but start change/remove.
What you can do:
Don't use Windows Installer (and WIX), use ZIP for example, or some self-extracting archive, or some other program which does not register installed product in the system.
Use command line to change product id before installing if you want MSI and Windows Installer for whatever reason. Try googling on "use transforms to install the same MSI multiple times". Thus you can have the same MSI per-transformed before installation, so that it looks as a different one to the system.
Install per-user, if that's good enough for you (i.e. don't install to Program Files, install to user folder)
Maybe there are other options...

How can a wix installer downgrade merge-module files during a major version upgrade?

We have an installer that consumes a merge module. The newest version of the merge module includes downgrades to some files. When using the installer to upgrade from an earlier version we are having problems downgrading these files.
Initially the files from the merge module were being removed and not re-installed, but after reading wix major upgrade not installing all files I set Schedule='afterInstallFinalize' on the MajorUpgrade element. This resulted in the files with the newer versions being retained.
How can we change either our installer or the merge module so that these files are downgraded during an upgrade?
Well, in my opinion, the best way to approach this issue is to sequence the standard action "RemoveExistingProducts" to before CostInitialize standard action.
Be aware that this scheduling is not in accordance with the Microsoft recommendation at :
https://msdn.microsoft.com/en-us/library/windows/desktop/aa371197(v=vs.85).aspx
So, when you try to build your msi package, you might have to end up suppressing ICE error messages ,which if not suppressed, might prevent you from building.
There is an easy way to suppress ICE error messages in Wix . You can do that in the Visual studio IDE as well as when using the candle.exe to compile your .wxs project. The Wix documentation will give you enough details about this.
If you are wondering if its ok to go against the Microsoft recommended placement for RemoveExistingProducts, take a look at :
Downgrade File in MajorUpgrade
FWIW, I've talked to MS support in the past about having REP before costing to make upgrades work successfully, and at that time they said it was ok, while pointing out that it's also before MigrateExistingFeatures so if you migrate features during upgrades there'll be an issue.
What this means is that , if you have multiple features in your msi package and you want the exact same set of features to be upgraded by your upgrade package, then this approach might not work.
However, if you just have a single feature in your msi package, then this approach will work.
Also, be aware that placing RemoveExistingProducts outside of InstallInitialize and InstallFinalize has other consequences, in case there is an error during your upgrade, as RemoveExistingProducts is not transacted.
What might happen is that , RemoveExistingProducts will uninstall your old application and then the upgrade process starts the installation of your newer version of your product. However, at this point of time, if there happens to be an error installing your newer version of your product, then the upgrade rolls back and then you will be left with no version of the product on your system.
http://blogs.msdn.com/b/heaths/archive/2010/04/09/major-upgrades-with-shared-components.aspx
-The other option is to make use of REINSTALLMODE property.
You will author this property in your property table with a value of emus
REINSTALLMODE = emus.
If emus doesnt work, try with amus.
using amus is fraught with risks and should be avoided for the most part, except in exceptional circumstances.
https://msdn.microsoft.com/en-us/library/aa371182(v=vs.85).aspx
However, exercise caution here again.
REINSTALLMODE are caller properties and are usually set by the person performing the installation and hence its not a good practice to author this in the Property table.
However, there might be exceptional situations such as yours which might require you to take this approach.
-The other option i was thinking was to change the component GUIDs of the components in your Merge module.
However doing so would only work if the following condition is met:
-All the consumers of your merge module have RemoveExistingProducts sequenced very early in the upgrade cycle i.e they follow a method of ugprade where the older product is uninstalled and a newer product is installed.
So this might lead to re-sequencing of RemoveExistingProducts in all of your consumers.
Reason being, assume for a moment that you change the component GUID in the present version of the merge module and then you rebuild the latest version of the installer using this merge module. If RemoveExistingProducts is sequenced later in the upgrade cycle i.e after InstallFinalize, then it's a violation of windows installer component rules. You have two products installing the same file to the same location but with different component GUId's. Hence, its absolutely critical that if this approach is followed, RemoveExistingProducts is sequenced very early in the upgrade cycle.
Hope this helps.