Update and retain web.config file during upgrade in wix installer - wix

What is the standard way to handle web.config files during major upgrade.I'm aware how the unversioned files are handled during upgrade,the file will not be replaced if the file has been modified by the user.
Is there a way to deal with the scenario where in there are new entries added to config file bundled with the latest installer that needs to be installed,and also retain the existing entries modified by the user during major upgrade in Wix.

The simple solution that a lot of my customers have liked is to not put user data in the web.config. Instead we use the AppSettings#file and ConnectionStrings#ConfigSource elements to specify an override file and keep the user data there. What MSI doesn't know about it won't tamper with. Now you don't have to be an MSI component rules wizard.
https://msdn.microsoft.com/en-us/library/ms228154(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/system.configuration.sectioninformation.configsource(v=vs.100).aspx

I know the question is for Wix, but just wanted to point out how much time commercial tools can save in such scenarios.
For example, using Advanced Installer you can read and load into an MSI property any XML values and then use the XML Files updater to write dynamic content in the files, at install(upgrade) time. (check the videos at the end of each article for a quicker overview)
Disclaimer: I work on the team building Advanced Installer.

Set the component to always overwrite and write a custom action to add the needed information to the config file.

The only way that seems possible is a custom action to merge the entries in the new file into the existing file, because you want data from the existing a new files. You would also need the upgrade scheduled late (after InstallExecute) so that the upgrade isn't an uninstall of the old product followed by an install of the new product.
If you are doing an upgrade (the WIX_UPGRADE_DETECTED property will be set by a MajorUpgrade element), so update the existing file, otherwise install the new one.
There might be a way to express the updates as an Xml transform, so something in the WiX util:xml tools might help do an update.

Related

Alternative to WiX Patch

I have an MSI, which adds a registry key, installs and starts some services, installs a file and so on. Now, there is a requirement to update one file and add a new file. I know we can create a Patch by creating a difference / transform. But in my second MSI, I only want to include these 2 files (the updated one and the new one) and not the other files, probably like a HotFix. I don't want to create a Patch. I did try to create a separate MSI but with the same UpgradeCode but with a different Product ID and a different version. But this creates a new entry in Programs and Features. Also, while uninstalling this new MSI, it does rollback the new file, but it doesn't rollback the modified file (this file was originally created by the first MSI and modified by the second one). At least if it is able to rollback and restore the state during uninstallation, it would have been great. But it is not rolling back the modified file properly.Has anyone come across this scenario? If so, have you been able to find a solution without a Patch? Please help.
There are three ways to update an installed product: a patch, a major upgrade and a minor upgrade. Although you can create a new MSI that replaces some of the files in an existing product what you are actually doing is sharing them in the same way that Microsoft Dlls (for example) are shared between many different products. (Unless you use the same component Ids and share properly you are more likely to break the product instead of updating it.) This is why you see that behavior of preserving files.
The idea that the patch may contain "contain other changes also which he is not interested in" should not be an issue. You create the patch so that it contains only those changes. It will contain other changes only if you put them in the MSI file when you create the patch.
Adding files during a patch can be tricky because there are some rules involved.
The safest thing to do is a major upgrade when adding new files.
So the choces are:
A patch that contains only the required updates.
A major upgrade, which is the complete new MSI file that upgrades the product.
A minor update which again is the complete new MSI file with the same ProductCode, incremented version, only minor hotfix changes, install with a special command line that includes REINSTALL=ALL REINSTALLMODE=vomus
Only the patch can be made to include just the changes required.

How can the contents of an installed file marked Permanent="No" be preserved during an upgrade?

Installers of previous versions of our software include a Component File that was NOT marked with Permanent="Yes". Now, we wish to read the pre-upgrade contents of this file during the upgrade process, which will overwrite the file with different contents. Is there a good way to do this?
It would help if you said exactly what you were doing that would cause the file to be overwritten. Some major upgrades (is that what you're doing?) will do a complete uninstall of the product first, followed by a complete install of the newer product. If that's the situation then use a custom action sequenced before RemoveExistingProducts to back up the file somewhere so that your application can retrieve the content, or get the content you need before it's ovewritten.
If you are doing a major upgrade sequenced later (such as afterInstallExecute) or you are doing a patch then it is by no means certain that the file will be overwritten because file overwrite rules will not replace a file that has been updated since it was installed. If the application altered the file then this type of upgrade will not overwrite it:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370531(v=vs.85).aspx
Or in the case that the file is unchanged since it was installed, change the dates so it appears to be modified, as described here:
https://blogs.msdn.microsoft.com/astebner/2013/05/23/updating-the-last-modified-time-to-prevent-windows-installer-from-updating-an-unversioned-file/
It's also not clear that Permanent=yes is what you want anyway - that would glue the file to the system forever. You may be thinking of NeverOverwrite, but it's typically not required if the app changes the files, and easier to decide at upgrade time (by changing dates) instead of committing to NeverOverwrite when it's sometimes unclear what the product may need in the future.
A comment refers to retrieving the previous version of the product during the upgrade. There are a number of ways to do this:
If you know the ProductCode of the previous version, MsiGetProductInfo (and equivalents in script etc) will return product version values or strings:
https://msdn.microsoft.com/en-us/library/aa370130(v=vs.85).aspx
Or if you'd rather not hardcode the value, MsiEnumProducts passing the UpgradeCode will return a list of installed ProductCodes. This technique is most useful if you have your own bootstrapper or UI where you want to show the user the current installed version.
In a WiX major upgrade the associated property (WIX_UPGRADE_DETECTED) is a list of the ProductCodes detected (usually a list of one) so you can use that to get the version of the product being upgraded. In a small vbscript example, something like:
set installer = CreateObject("WindowsInstaller.Installer")
and:
prodversionstring = installer.productinfo(WIX_UPGRADE_DETECTED, "VersionString")
will get you close.
Assuming this file is a configuration file such as an XML file, I find this is just a tough area of Windows Installer. You ship file version 1, the end user modifies certain attributes and then you ship file version 2 to which you want to preserve those customizations.
The problem is this is a very complex merge. It works somewhat OK if you only care about 1-2 attributes but if the answer is I need to preserve all of it then you are stuck between losing all the customizations or not getting the changes from version 2 of the file.
You could write extensive custom actions to do all this during the installer but I propose there is a better way: Have 2 files.
1 file that is owned by the installer and can always be safely overwritten and 1 file that is owned by the application that overrides are stored in. Think of it like a transformation file. The installer doesn't know about this file so it never overwrites or deletes it. (The very definition of user data from an MSI perspective.)
For example the .NET framework Web.Config schema AppSettings element has a file attribute that was designed to support this nicely.
Specifies a relative path to an external file containing custom
application configuration settings. The specified file contains the
same kind of settings that are specified in the , , and
elements and uses the same key/value pair format as those
elements. The path specified is relative to the main configuration
file. For a Windows Forms application, this would be the binary folder
(such as /bin/debug), not the location of the application
configuration file. For Web Forms applications, the path is relative
to the application root, where the web.config file is located.
Note that the runtime ignores the attribute if the specified file can
not be found.

Wix custom action is failed to load the dll file?

I am trying to do a custom action at the time of msi installation. But the dll required for my custom action is depends on other dlls. At the time of installtion it is giving the error like "a dll required for this install to complete could not run".How can I load the dependent dll files for this custom action to run properly.
The code that I am using is
<CustomAction Id='CheckingPID' BinaryKey='CheckPID' DllEntry='ValidateKey' />
<Binary Id ='CheckPID' SourceFile='$(sys.CURRENTDIR)\LicenseKeyClient_32d.dll'/>
<Binary Id ='CheckPID2' SourceFile='$(sys.CURRENTDIR)\curllib.dll'/>
<Binary Id ='CheckPID3' SourceFile='$(sys.CURRENTDIR)\libsasl.dll'/>
<Binary Id ='CheckPID4' SourceFile='$(sys.CURRENTDIR)\openldap.dll'/>
The files that you add in binary table usually get extracted with temporary names during the installation, so your DLL will not be able to locate the other DLLs you add next to it.
A workaround is to add those DLLs as normal files in the Temp system folder and delete them when the installation ends. This has the limitation that you need to set your custom action as deferred, so it executes after the files are installed, thus your DLLs get copied to Temp folder.
I don't know if wix has a support for temporary files, similar with the one present in Advanced Installer, but if not you could try to write a custom action to simulate it. Basically what Advanced Installer does is to extract those files in the Temp folder the moment the MSI is launched, and also deletes them when the installation is complete. This has the advantage that you can use the temporary files and in immediate custom actions, i.e. well before the files from your package are installed.
Despite Bogdan's excellent answer, allow me to add my 2 cents:
It looks like you are dealing with some form of license key validation? The best way is generally to deal with your license keys in the application itself, unless you want it written to HKLM instead of HKCU - in which case you might need the temporary admin rights generally acquired during installation.
You can also open a HKLM key for writing during setup, and write it from the application though this is generally frowned upon security-wise. This allows you to write a single license key for all users directly from the application.
The application features more flexibility and control of the process of registering your license key, and crucially an easy way to run the process again. From my perspective this is almost always needed for a serious application - often due to trial versions with the eventual need to register the license key at the end of the trial period from within the application itself - instead of uninstalling the application and reinstalling, or running the setup in repair / maintenance mode - which seems extremely clunky.
I have described this issue previously in some more detail: Reasons to deal with licensing in the application rather than the setup.
I'll also add that WiX DTF .NET custom actions really simplify this problem by allowing you to embed content into the self extracting custom action package and make them available in the current directory at runtime. Very easy.
But yes, Glytzhkof is correct. Any licensing / DRM done inside of an MSI is easily defeated. It's best to do this in the app or both. For example I've worked at companies where it's a share responsibility. You can enter one now or later. I've also worked at companies where the license key had bits embedded in it that drove feature selection. It gets complicated fast so try not to have to go down that road.

Merge Existing Config File in Wix

I'm using WiX 3.8 and trying to update my existing .config file on minor update but I'm having difficulties understanding how to achieve this.
I created a custom action to read values from the existing config file but can't figure out how to insert them into the new file?
I followed this article : Having WiX upgrade a config file with missing items (and subsequently this one : How can multiple elements be added to an XML config file with wix?) but
settings don't seem to be getting overwritten with previous values, can anyone give me a pointer please?
Basically I want to preserve the settings entered by the user during installation but overwrite the rest of the config if it has changed from version to version.
In a nutshell, this is a huge weakness of Windows Installer. Natively MSI has no support for XML operations. At it's core, Windows Installer treats files atomically where as an XML file is in a sense like an entire registry hive.
WiX adds in XML transforming capabilities to solve the first problem but the second problem is really impossible to solve. You'd have to have a copy of the original XML, the current XML and the proposed XML and then you'd have to have business rules to know what to merge and what not to merge.
In order to avoid this problem in the first place, what I personally suggest is to have 2 XML files. One installed and fully owned by the installer ( stock.xml) and one not touched by the installer and owned by the application (override.xml). Then in your XML reader have the contents of the override.xml take precedence over the contents of the stock.xml. In this way the installer can always do what it does best ) install files without having to do complicated data processing.
I currently do this with a combination of custom action and XmlConfig.
The custom action is run after CostFinalize and reads current values from the config file(s) and saves them in public properties.
string configFile = Path.Combine(session["INSTALLLOCATION"], "app.exe.config");
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = configFile;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
session["OLD_PRESERVEDVALUE"] = config.AppSettings.Settings["PreservedValue"].Value;
then I have an XmlConfig entry like below which sets the preserved values from the public properties:
<Component Id="RestoreOldPreservedValue" Guid="<GUID>" >
<Condition>OLD_PRESERVEDVALUE</Condition>
<CreateFolder/>
<util:XmlConfig
Id='RestoreOldPreservedValue'
Action='create'
On='install'
Node='value'
ElementPath='/configuration/applicationSettings/app.Properties.Settings/setting[\[]#name="PreservedValue"[\]]/value'
File='[#app.exe.config]'
Value='[OLD_PRESERVEDVALUE]'>
</util:XmlConfig>
</Component>
My next iteration will be to have the custom action create entries in the XmlConfig table directly.
The ultimate solution would be a WiX extension that populates a custom table and schedules a custom action which saves the values to be preserved after CostFinalize, and then another custom action that restores the values after the new config file(s) have been copied by the installer.

WiX How to remove a component marked as permanent

I am in the following situation where I need to remove a component which is marked as permanent.
A previous version of our setup installs a windows service which should be left on the system after the main product was uninstalled.
Now we try to remove the left service and replace it with an updated version. The problem is we have two different component guids out there, because of changing the tools we used to create the msi's.
In my opinion there are three possible ways to achieve the goal:
a) Use a file search to update the files itself.
b) Use a component search and try to find it. If it was not found try to find the other one. If any one found use the upgrade element to upgrade the component.
c) ??? - probably the "best practice" way
Some of my fellows mentioned to only delete the files but this would cause more trouble because of the not unregistered component in the Windows Installer registry.
I don't mentioned CustomActions here because it should be the last option the achieve the goal.
Your best option here is to open your old MSI using InstEd It! or Orca and then copy the Component GUIDs and use them in your new installer.
This way WindowsInstaller will handle the upgrade for you. Obviously this will very painful if you have hundreds of Components that are set as permanent (you only need to bother about the permanent ones), but if it's a just the service element it should be a fairly easy task.
Also make sure your UpgradeCode is transferred across and do a MajorUpgrade so that your old installer is un-installed first.