I have a WiX project making msi which replaces much older installation which was made by a set of scripts which unpacked zip files.
I'd like to specify that certain files in msi must force overwrite already existing non-versioned files from the old installation. Later it wouldn't be a pb as msi to msi update would be an upgrade.
Is it possible to specify on a per-file basis that msi must overwrite old non-msi installed files?
I will add some links for you and a summary.
Yes, you can overwrite single files by various means and you can even
force downgrade files setup-wide, but the latter is terribly dangerous
to do (information on dangers in section 4 here).
Ensure Overwrite: This answer describes various measures to always-overwrite files: Ensure file overwriting - with a WiX example. Here is an alternative answer.
The use of companion files is what I would recommend.
Hacking file versions I do myself sometimes - just to make things work.
I prefer to move or rename files to "remove the problem".
See the above links for more on the above "options".
Further information:
On file overwriting in general - step-by-step (describes the REINSTALLMODE property and the problems that are caused by using it to force-downgrading files during installation)
Related
I have a WiX Managed Bootstrapper Application that installs some MSIs. I also have a series of tests that exercise the various functions of the installer. The problem I'm having is with the repair test. The test purposely corrupts all the DLLs we install then calls the EXE installer with "/repair /passive" flags. Once completed around 80% of the DLLs are repaired but the remaining ones are untouched and therefore still corrupted after the repair.
If I manually run msiexec on an individual MSI with the command line args "/fa" which instructs the MSI to forcibly replace all the files it installed, it fixes 100% of the DLLs.
My question is how can I force the MBA to instruct each MSI to repair in this way? I've tried setting the REINSTALLMODE property to 'amus' on the individual MSIs in their .wxs files but the MBA overwrites them at run time as is evident in the log via this line:
PROPERTY CHANGE: Modifying REINSTALLMODE property. Its current value is 'amus'. Its new value: 'cmuse'.
I've also tried to set the properties in the MBA to pass through to each MSI but it doesn't appear to pass them and instead uses it's default values.
I see many similar questions here but none actually address this specific issue. Any help would be greatly appreciated. Rob save me!
Here's your problem right here:
[12:25:25:874]: File: C:****\estimator.dll; Won't Overwrite; Won't patch; Existing file is unversioned but modified
The installer doesn't want to overwrite a file that has changed since it was installed if it cannot verify the version or language (and maybe some other properties?). Without these properties, it decides to look at the modified date. If it is newer than when it was first installed then it won't touch it assuming instead that something changed for a reason and reverting it will cause something to fail. (You can read more here)
One thing you can do in this case is use a Companion File
Set this attribute to make this file a companion child of another file. The installation state of a companion file depends not on its own file versioning information, but on the versioning of its companion parent. A file that is the key path for its component can not be a companion file (that means this attribute cannot be set if KeyPath="yes" for this file). The Version attribute cannot be set along with this attribute since companion files are not installed based on their own version.
Basically you will set the logic for installing/uninstalling this component to be the same as the "FileID" of another component in the install. In the estimator.dll component, in the File tag, remove KeyPath="yes" and instead replace that with CompanionFile="<NameOfAnotherFileID>".
The issue with this approach is that you may have a corrupted DLL but the companionFile it was linked to was fine so it is not reinstalled.
If this is a dll you do own, I would highly suggest versioning the file! Give it any version you want and this issue should go away.
Another thing you can try, although I don't know how it works really, is giving the file a DefaultVersion
This is the default version of this file. The linker will replace this value from the value in the file if the suppress files option is not used.
This would be the quickest solution to verify. Just build a new installer with DefaultVersion="1.0" in the estimator.dll's <File> and see if it gets replaced. I think this will have the installer think the file is versioned 1.0 but the installed file is not versioned so it will replace it (see here)
As I put in title, the question is how does Wix decide to install a particular file?
So I have exe file and when I change something in exe file and rebuild it, it will not get reinstalled if I don't change version. But if I change something in resource file, resource file will be replaced even if I don't change version of my application. So how wix is deciding if he need to replace file during upgrade or not.
I am using wix3.9. MajorUpgrade is schedule afterInstallFinalize.
Versioned files get replaced based on file version, yes, but data files get replaced based on whether you have specified file hash or not. I think WiX generates file hases by default, so this is the overwrite rule:
https://msdn.microsoft.com/en-us/library/aa370532(v=vs.85).aspx
and it's a Windows Installer rule that applies to all MSI settup, not a WiX decision.
P.S. afterInstallFinalize isn't an ideal place. afterInstallExecute is safer, and it will have the same overall result. The issue is that after InstallFinalize means that the new product is installed. If the uninstall of the older product then fails and rolls back you will end up with both old and new products installed, otherwise known as a mess. afterInstallExecute makes everything part of the transaction so you get the original product installed if there is a failure to uninstall it.
I have an MSI that setups my application. It has a single component and installs only to %PROGRAMFILES% (no shared binaries). Simplified, it looks like this
Msi file, Monday build:
Program.exe (v1.0.0)
ThirdPartyLibrary.dll (v2.0.1)
Now, if I discover a bug in the program caused by my upgrade of the ThirdPartyLibrary dll from v2.0.0 to v2.0.1, and thus revert the reference to v2.0.0, it seems my MSI doesn't automatically replace the file in the installation directory?
Msi file, Tuesday build:
Program.exe (v1.0.0)
ThirdPartyLibrary.dll (v2.0) <- downgraded
What is the best practice here to ensure that the program folder always contains exactly the binaries in my setup? Should I a) wipe everything from the setup directory before copying the new files? Is there an option (in Wix) I can use that makes the msi force an overwrite of all files regardless of version?
What if I remove a file from the setup (a file that would cause errors if present at runtime), then the only way to have a working program after the setup, would be if it deleted all files first?
You can use a msi trick. In the File table in the msi database edit the Version column and enter a higher version, 3.0 for example. This way you will take advantage of the file versioning rules.
I'm working on the upgrade feature for my WiX-based installer.
As part of the instalation, we are installing a web.config file and then using a custom action to update the connection strings inside the file.
But this causes a problem when we run our upgrade. We would like to have the RemoveExistingProducts scheduled for after InstallFinalize since this is most efficient in terms of not removing and reinstalling files that have not changed. But this leaves the original web.config file in place at the time when Windows Installer is trying to determine whether it should update it or not. Since it's last modified date is more recent than its creation date, Windows Installer decides not to update it (see versioning rules that Windows Installer uses). But we need it to be updated.
One obvious solution is to change the scheduling of RemoveExistingProducts to after InstallValidate - but this is inefficient, and also, I don't think it would give us the opportunity to migrate settings from existing files, should we need to do that.
Any other ideas?
Newer answers: 1) Companion files, 2) file version hack using Visual Studio, 3) moving the file to another installation path, 4) variations of REINSTALLMODE, 5) "version lying", etc... All kind of options, most of which are not ideal:
File of a new component isn't installed because there was an old component with the same file
How to Explicitly Remove dll During Majorupgrade Using Wix Toolset
Below is an older answer. I don't think option 2 works properly anymore:
There are many ways - none are ideal.
1: You can use a companion file to force update of the file in question. Provided the companion file specified always gets updated, this may be the way to go. Essentially this means that you link the non-versioned file to the version update logic of its companion file (files are updated together). I have never used this in WIX, but I think it's as easy as adding the CompanionFile attribute to a File element and point to the ID of the file you want to "version follow". Inside the MSI file it will look something like this:
2: You can use a custom action to delete the file before file costing (or better yet, rename it to a backup format). The problem is that if the setup fails the file will be missing. If you rename the file instead of deleting you can put it back in case the setup fails via a rollback custom action. Sometimes I use the RemoveFile table to remove files on install, but depending on the sequencing specified in InstallExecuteSequence this may not work (deletion must happen before msi does file costing).
3: Then there is the sledgehammer approach: set REINSTALLMODE = amus to force overwrite all files regardless of version. I shouldn't even mention this since it is horribly dangerous (you can end up overwriting system files, or on newer Windows versions trigger a nasty runtime error as files are protected). Use it only for dev testing, and don't think it is a quick fix. It causes more problems than it solves.
As a variation, an acceptable approach may be to set the REINSTALLMODE to emus (replace older and same version files). This can help if you don't want to increment the version numbers but keep rebuilding your binaries - as is the case in a lot of .NET. My guess is this will cause a whole new range of problems though - most significantly binary different but version identical files in the wild if you use it for public releases - a deployment smell if ever there was one. As a QA/DEV only approach it could work though. But seriously, why bother? Just auto-increment the build version of the binaries and the problem is solved reliably.
Links:
How to Explicitly Remove dll During Majorupgrade Using Wix Toolset
Only iffy ones. You could remove the specific file early with a custom action, but be sure to condition this right! Or you could specify a version for the file so upgrade rules will treat it like replacing a non-versioned file with a versioned one, but then patches can get antsy about having the wrong version of this file.
Don't use a custom action to update your config file is the other obvious idea. Instead get WIX to do the update via the XML extensions. E.g.
<Component Id="web.config" Guid="f12ff575-ad5f-47bc-a5c9-40b1e3a7f9f5" >
<File Source="$(var.SrcPath)\web.config.config" KeyPath="yes" />
<util:XmlConfig Id="AppSqlInstanceName"
File="[#web.config]"
Action="create"
ElementPath="//configuration/connectionStrings/add[\[]#name='YourStringKey'[\]]"
Name="connectionString"
Node="value"
Value="metadata=res://*/YourModel.csdl|res://*/YourModel.ssdl|res://*/YourModel.msl;provider=System.Data.SqlClient;provider connection string="data source=[SQLSERVERANDINSTANCE];initial catalog=DatabaseName;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework""
On="install"/>
</Component>
This is using a [SQLSERVERANDINSTANCE] variable which needs to be setup before hand.
I am creating an install package using InstallShield Pro X. The upgrade works properly. However, the product manager wants the upgrade to replace all files on an upgrade even if the create date != modify date on the file.
I see that to do this I need to set REINSTALLMODE=vamus rather than vomus. However, I don't see how to tell InstallShield that I want it to use that setting. By default setup.exe always passes vomus to windows installer.
There is a property in the InstallShield project named ReinstallModeText that I changed from omus to amus but that seemed to have no effect.
So, how what do I set in the install project so that when setup.exe detects to run an upgrade it sends REINSTALLMODE=vamus? Thanks.
Update: Tried adding the following to the MSI Command Line value in the Release section:
REINSTALLMODE=vamus
This did not work. Setup.exe didn't set REINSTALL=ALL on the command line what I did this. I added that to the MSI Command line and the upgrade worked as expected. But, not the problem is if it is a NEW install those properties are still being set and the installer fails.
In investigating this further and testing more options I think the best answer is to modify the product code in addition to the product version and author it as a major upgrade which removes the previous version first and then installs the new files.
The main problem with this is that it takes alot longer for the installer to run. I also think that you can not issue this as a patch, but I could be wrong on that count.
Don't set the REINSTALLMODE to amus or vamus (force overwrite files). These settings apply to all components in the MSI, and could hence in theory downgrade system files or at least shared files - this typically involves files included via merge modules. It is normally safe to set REINSTALLMODE to emus (replace files with lower or equal version number). Even this can trigger a file replacement error if you try to overwrite a system protected file on newer versions of Windows featuring Windows Resource Protection (wikipedia) (Windows Server 2008 and Vista onwards). On older Windows versions the file would likely be overwritten and then restored in its right version from the dllcache via the Windows File Protection feature provided that feature had a good day. There was (and is) an associated tool for system file checking: System File Checker.
If you have issues with files that should be replaced even if they have been edited, you can use the RemoveFile table to schedule the file for removal during install (and then it will be reinstalled).
The real solution is to consider the installation folder in %ProgramFiles% as read only, and not have the application save ANY settings or change any files. All config files should go to the user profile or the alluser profile and the application EXE file should be responsible for the copy to the profile locations.
See my answer here.
I don't have IS X handy, but in later versions of InstallShield you would go to "Releases", highlight your release, go to the "Setup.exe" section and there's a field called "MSI Command Line Arguments". There you would indicate any command-line arguments that you want Setup.exe to pass to Windows Installer. E.g. REINSTALLMODE=vamus
You mentioned you used ReinstallModeText with "amus". Have you tried ReinstallModeText equal to "vamus". The "v" causes the installer to run off the source package, not the cached package, and that may be your problem.