Editing file with msi-installer - wix

I need update some software without replacing software's config-file. But this config-file must be upgraded (add some lines). Is it possible to edit the config-file with msi (created by wix) without replacing it?
<Component Id="com6e3e974d3fe541ed8554485c716e6f40" Guid="{841fb431-8a04-4ee8-a53f-80a5af8f3aa3}">
<RemoveFile Id="A21" Name="N4GWSRV.exe.config" On="install" />
<File Id="fil20a15c96a7db4fa7924651e80c05764e" Name="N4GWSRV.exe.config" KeyPath="yes" DiskId="1" Source="C:\ATM\N4GWSrv\N4GWSRV.exe.config" />
</Component>

Thanks to Adrian Faciu for link How to modify .NET config files during installation?
also helped http://blogs.technet.com/b/alexshev/archive/2009/05/27/from-msi-to-wix-part-25-installable-items-updating-xml-files-using-xmlfile.aspx

Related

The target file 'XXXX' is installed in 'YYYY' by two different components on an LFN system

We recently upgraded DevExpress. Since we have a custom theme, we had to upgrade the custom theme too.
That was the easy part. Now I'm trying to upgrade the setup to match the new file.
So basically, I'm changing the <File .../> of one <Component .../>:
From
<Component Id="Lib_Various_Files" Guid="9C621EB0-12E6-4D1D-8B5B-4150A76E33AA" KeyPath="yes" SharedDllRefCount="yes">
...
<File Id="DevExpress.Xpf.Themes.PreviousTheme.v17.1.dll" Name="DevExpress.Xpf.Themes.PreviousTheme.v17.1.dll" ReadOnly="yes" Vital="no" Compressed="default" DiskId="1" Source="$(var.DirLib)\PreviousTheme\DevExpress.Xpf.Themes.PreviousTheme.v17.1.dll" />
</Component>
To:
<Component Id="Lib_Various_Files" Guid="9C621EB0-12E6-4D1D-8B5B-4150A76E33AA" KeyPath="yes" SharedDllRefCount="yes">
...
<File Id="DevExpress.Xpf.Themes.OurTheme.v17.2.dll" Name="DevExpress.Xpf.Themes.OurTheme.v17.2.dll" ReadOnly="yes" Vital="no" Compressed="default" DiskId="1" Source="$(var.DirLib)\OurTheme\.td\Publish\DevExpress.Xpf.Themes.OurTheme.v17.2.dll" />
</Component>
Now I've an error in the setup, which seems to have no links to this line:
error LGHT0204: ICE30: The target file
'qgikh9i6.dll|System.Windows.Interactivity.dll' is installed in
'[TARGETDIR]\OurProduct\Bin\' by two different components on an LFN
system: 'cmpF5730C92213BA3272DDA3A5657DFF782' and 'Lib_Prism'. This
breaks component reference counting.
[D:\ws\OurProduct-Nightly\SetupWix\SetupWix\SetupWix.wixproj]
We do reference this library, in the Lib_Prism component(which is then in another Lib_Various component, that reference Lib_Prism and Lib_Various_Files, but nowhere else.
Any idea what could be the issue?
So here is the complete components list of this file:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<?include ..\Common.wxi?>
<DirectoryRef Id="BIN">
<Component Id="Lib_Various_Files" Guid="9C621EB0-12E6-4D1D-8B5B-4150A76E33AA" KeyPath="yes" SharedDllRefCount="yes">
...
<File Id="DevExpress.Xpf.Themes.OurTheme.v17.2.dll" Name="DevExpress.Xpf.Themes.OurTheme.v17.2.dll" ReadOnly="yes" Vital="no" Compressed="default" DiskId="1" Source="$(var.DirLib)\OurTheme\.td\Publish\DevExpress.Xpf.Themes.OurTheme.v17.2.dll" />
</Component>
<Component Id="Lib_MicrosoftPractices" Guid="780097FD-40C9-417A-A2C3-7C2B44567BEC" KeyPath="yes" SharedDllRefCount="yes">
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll" />
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.Configuration.dll" />
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll" />
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.dll" />
</Component>
<Component Id="Lib_Prism" Guid="0F937515-2248-4CD2-B2E9-3E121FA9D743" KeyPath="yes" SharedDllRefCount="yes">
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\Prism.Core.6.3.0\lib\net45\Prism.dll" />
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\Prism.Unity.6.3.0\lib\net45\Prism.Unity.Wpf.dll" />
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\Prism.Wpf.6.3.0\lib\net45\Prism.Wpf.dll" />
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\Prism.Wpf.6.3.0\lib\net45\System.Windows.Interactivity.dll" />
</Component>
<Component Id="Lib_MvvmValidation" Guid="8681DBA1-F83D-475B-BCB8-A54A1F05FF0A" KeyPath="yes" SharedDllRefCount="yes">
<File ReadOnly="yes" DiskId="1" Source="$(var.DirPackages)\MvvmValidation.3.1.0\lib\netstandard1.0\MvvmValidation.dll" />
</Component>
<Component Id="Lib_Protobuf_Net" Guid="AEE6F4EB-78E3-4EC5-AA88-D5CC29D683D0" KeyPath="yes" SharedDllRefCount="yes">
<File ReadOnly="yes" DiskId="1" Source="$(var.DirDotfuscated)\ProtobufNet.dll" />
</Component>
</DirectoryRef>
<ComponentGroup Id="Lib_Various" >
<ComponentRef Id="Lib_MicrosoftPractices" />
<ComponentRef Id="Lib_Prism" />
<ComponentRef Id="Lib_Various_Files" />
<ComponentRef Id="Lib_MvvmValidation" />
<ComponentRef Id="Lib_Protobuf_Net" />
</ComponentGroup>
</Fragment>
</Wix>
Looking at your source file there are several problems with your component reference counting outright. You should never install several binaries with one component - it is a direct violation of the component rules. This causes exactly the kind of problems the error message indicates.
I recommend using a single file per component because that solves a plethora of possible reference count issues and upgrade problems. The shared-dll ref counters can also cause some blues I think. Do you have a legacy installer that you are trying to be compatible with? If not, then there is no reason to enable this component option - it increments the legacy SharedDLL ref-counter used by older, non-MSI installer technologies.
Now, for the issue where you change a file name in an existing component. This is also a violation of the component rules. You can not change the absolute file name of a component's key path and keep the same component GUID - this breaks component referencing. There must be a 1-to-1 correspondence between an absolute installation path and a component GUID.
The component GUID doesn't follow the file around if it moves, and the file "moves" when you change its file name (its absolute installation path has changed). There is an explanation here with an example: Change my component GUID in wix? (recommended read - decode this MSI peculiarity and things will be clearer going forward).
If you change a file name you can either:
Set your component GUIDs to auto-generate by deleting the whole GUID section in your source. The GUID will then be generated to be stable as long as the installation target path remains the same, and when you change the file name - for example - a new GUID will be generated for you auto-magically by WiX. See this answer for sample: Syntax for guids in WIX?
Set a new, hard-coded GUID yourself for the components where you change the file name that is being installed. This can be easy to forget - hence the recommended auto-magic described in point 1.
What you should actually do when file names change is to remove the old component and add a new one with the new file name. However, changing the GUID of an existing component and changing the file name has the same effect (same as deleting the old component and adding a new one).
With that said, there are bigger problems with this source as explained above. For future reliability you must split these components into one file per component. This causes interference between your old and new version and in order to clean this up, you can:
Set a totally new installation path for your project and use a single component per file from now on and you can use WiX's auto-magic component generation feature as explained above. This will work. Setting a new main installation folder "breaks the link" to "past component referencing sins".
Or you can uninstall the existing installation early during your major upgrade by moving RemoveExistingProducts early in the InstallExecuteSequence of your newest MSI version. This also wipes the slate clean of any component referencing issues and you can change your source to use one file per component going forward. If you use the MajorUpgrade element this change is easy - just set Schedule="afterInstallValidate". That should work (no time to test).
That should be it - if I have understood your scenario correctly.
Sample WiX extract for the proposed, new version:
<DirectoryRef Id="BIN">
<Component Feature="Product">
<File Source="$(var.DirLib)\OurTheme\.td\Publish\DevExpress.Xpf.Themes.OurTheme.v17.2.dll" />
</Component>
<Component Feature="Product">
<File Source="$(var.DirPackages)\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll" />
</Component>
<Component Feature="Product">
<File Source="$(var.DirPackages)\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.Configuration.dll" />
</Component>
<Component Feature="Product">
<File Source="$(var.DirPackages)\Unity.4.0.1\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll" />
</Component>
<...>
</DirectoryRef>
Notice the tersified source with all attributes that can be auto-generated left out and all components now containing a single file. There is also direct specification of what feature each component belongs to as an attribute of the Component element. I find that this yields the least complicated and most flexible WiX source files. Preferences vary - obviously.
I would not roll with your current "multiple binaries per component" setup going forward. There will be more trouble if you do - almost guaranteed. MSI bites back - sorry to say - there are many bear traps. MSI has aspects that border on anti-patterns. The problems are faced by almost everyone. There is a section towards the bottom here on potential anti-patterns and also on the great benefits MSI yields for corporate deployment (just for reference): How to make better use of MSI files.
I am not particularly keen on this chaotic write-up of common MSI problems, but here it is: How do I avoid common design flaws in my WiX / MSI deployment solution? Maybe it can help to avoid some very common problems.
I finally found the issue:
It appears that DevExpress bin directory packs the System.Windows.Interactivity.dll library. So before we were not copying it and we didn't had it in our Lib\DevExpress folder.
It appears that we generate a componet with all Dll contained in the Lib\DevExpress folder, and therefore the System.WIndows.Interactivity.dll was contained in 2 differents packages.
I removed it from the DevExpress folder and now everything works fine. Sorry for the trouble.

How to create msi installer which can install file located near by it?

How to create msi installer which can install file located near by it or fetch this file over http?
We want to create an msi installer with wix toolkit 3.9 that should distribute our virtual machine (size is bigger than allowed in cab files), hypervisor, register(unregister) powershell scripts and something else.
We cannot create MSI with big file.
I see two approaches:
We can put virtual machine image located near by msi installed and programming this installer to install image if it exists near by it.
d:> dir
myapp.msi
vm.vdi
We can agree with client that he must put vm image located near the msi installer manually, before run it.
Download this vm image with http. What are the options for this?
How I can do this ?
I do this like this:
<!-- This is a list of directories that are used by this product as installation locations or custom -->
<!-- action file search locations. -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder" Name="AppData">
<Directory Id="AppRootDirectory" Name="Lookd"/>
</Directory>
</Directory>
<DirectoryRef Id="AppRootDirectory">
<Component Id="SupplementalScripts" Guid="31693357-578d-4dde-aefc-92f413942810" KeyPath="yes" DiskId="1">
<CreateFolder/>
<RemoveFolder Id="RemoveAppRootDirectory" On="uninstall" />
<File Id="SupplementalScripts_Register" DiskId="1" Vital="yes" Source="dst\Scripts\Register.ps1" Checksum="no"/>
<File Id="SupplementalScripts_UnRegister" DiskId="1" Vital="yes" Source="dst\Scripts\UnRegister.ps1" Checksum="no"/>
<File Id="SupplementalScripts_Throw" DiskId="1" Vital="yes" Source="dst\Scripts\Throw.ps1" Checksum="no"/>
<RegistryKey Root="HKCU" Key="Software\CVisionLab\Lookd" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Name="Version" Value="[ProductVersion]" Type="string"/>
</RegistryKey>
</Component>
<Component Id="VirtualMachineDiskImage" Guid="daa7375f-7bd8-4e97-846a-db5f6e6b025a">
<CopyFile Id="VDIFile" SourceName="lookd.vdi" SourceDirectory="SOURCEDIR" DestinationDirectory="TARGETDIR" />
</Component>
</DirectoryRef>
But I recive and error when build:
error LGHT0094 : Unresolved reference to symbol 'Directory:SOURCEDIR' in section 'Product:{7BBA165B-9A8A-40D1-97FA-233F93426F83}'.
If 1 will work for you, then a WiX CopyFile should work. The source location of the copy would be the [SourceDir] property, and the destination some directory defined in your WiX.
If it's really that big, download may be tedious, but if you use it then do it from an app you install rather than run it from the MSI install.
Clarifying in response to comment: there are just two recommendations here that are separate and not related:
Use WiX CopyFile if you choose to copy the file from next to the MSI file to the client system.
If you choose the download option, doing that from the MSI will be tedious and very error prone. It may not even work given that VS custom actions have very limited (or no) access to the network. So do a download from the app you're installing and not the MSI, if you do in fact decide to download.

WiX: Managed to not overwrite config file during upgrade, however shortcuts are removed

I have a similar problem like forki23 by bring Wix to not overwrite a configuration file during upgrade. I have a config file that should not be overwritten during upgrade, but it should be removed during uninstall. However every solution I find, breaks something else.
If I set NoOverwrite=yes and move the RemoveExistingProducts to InstallFinalize the config file is handled as I wished. However, in this case the shortcut is removed during upgrade for some reason. If I leave RemoveExistingProducts at InstallInitialize, the config file is actually removed during upgrade, however the shortcuts are present.
Why is this happening and is there are way to fix it?
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize" />
<!-- InstallInitialize causes config-file to disappear during upgrade -->
<!-- InstallFinalize causes shortcuts to disappear during upgrade -->
...
<Property Id="DISABLEADVTSHORTCUTS" Value="1" />
...
<Directory Id="INSTALLLOCATION" Name="MyApp">
<Component Id="MYAPP.EXE" DiskId="1" Guid="...">
<File Id="MYAPP.EXE" Name="MyApp.exe" Source="..." Vital="yes" KeyPath="yes">
<Shortcut Id="startmenuShortcut"
Directory="ProgramMenuDir"
Name="!(loc.ProductName)"
WorkingDirectory='INSTALLLOCATION'
Icon="Icon.ico"
IconIndex="0"
Advertise="yes" />
</File>
<RegistryValue Root="HKLM"
Name="InstallLocation"
Key="$(var.InstallLocationRegistryKey)"
Type="string"
Value="[INSTALLLOCATION]">
</RegistryValue>
</Component>
<Component Id="MYAPP.EXE.CONFIG" DiskId="1" Guid="..." NeverOverwrite="yes">
<File Id="MYAPP.EXE.CONFIG"
Name="MyApp.exe.config"
Source="..."
KeyPath="yes" />
</Component>
...
</Directory>
...
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgramMenuDir" Name="!(loc.ProductPrefix)">
<Component Id="ProgramMenuDir" Guid="...">
<RegistryValue Root="HKCU" Key="SOFTWARE\MyApp"
Type="string" Value="[INSTALLLOCATION]" KeyPath="yes" />
<RemoveFolder Id="ProgramMenuDir" On="uninstall"/>
</Component>
</Directory>
</Directory>
Note A: The config-file is a machine-wide configuration and should apply for all users.
Note B: I'm using WiX 3.7 and the target plattform is Windows 7 and 8.
Theoretically "NoOverwrite=yes and move the RemoveExistingProducts to InstallFinalize" should work, but it s clear we are losing something from the big picture. The best method to see why Windows Installer removes the shortcuts is to create a verbose log when launching the upgrade setup. You can do that in a cmd.exe with this command: msiexec /i [msi path] /L*V debug.log
The post the a download link for the log and the GUIDs of the components hosting the shortcuts so we can see if the log helps us understand what happens.
Windows installer works very exact in those things, and if anything gets removed in the After="InstallFinalize" case, this means, that a component has been removed, MSI has thought is not needed, because not contained in your new version of the msi file. Be very sure the GUID of the component containing MYAPP.exe and the shortcut has not changed in your new version. (Compare with a tool like Orce or Insted). It seems it has!
MSI removes only full components, not only shortcuts. Really! Maybe you have an update problem of shortcuts in Windows. Sometimes such things happen. Try to reboot to be sure, that this happens, what you think. Maybe there is an error in your test procedure (or it's the above mentioned GUID problem). There are not many other possibilities, if you have not custom actions which remove shortcuts or you try to add shortcuts as files or such dangerous stuff.
Putting a shortcut in the same component as the .exe is common, but not optimal in my eyes! I recommend to separate resources as much as possible, so put it in an own component. This has advantages, if you later want to rename the shortcut. Then you can just change the GUID of this component and the important .exe file is not touched.
There is a small disadvantage of that, loosing the direct connection to the file version of MYAPP.exe in overinstall scenarios, so if MYAPP.exe is a shared file between several different setups, this is not recommended. Perfect solutions for this are possible, but are not in the focus here.
Workaround: If you are still able to change the old (first) msi setup, just mark the component MYAPP.EXE.CONFIG as permanent. Then it will not be uninstalled during Major Upgrade (but not uninstalled at all, what has advantages and disadvantages, in other words, it is mostly acceptable for .config files).
If version 1 of your setup is already shipped, then you could do the same with some tricks too.

Which would be the proper way to install one publisher policy in to the GAC using WIX?

Which would be the proper way to install one publisher policy in to the GAC using WIX 3.5?
I tried to do this:
<File
Id="LIBGAC"
Assembly=".net"
KeyPath="yes"
Vital="yes"
Name="ClassLibrary1.dll"
ProcessorArchitecture="msil"
DiskId="1"
Source="..\ClassLibrary1\bin\Release\ClassLibrary1.dll" >
</File>
</Component>
<Component Id="Config" Guid="F089B1AA-B593-4662-9DF4-F47EB9FBA1F4" >
<File
Id="LIBGACPolicy"
Assembly=".net"
KeyPath="yes"
Vital="yes"
Name="Policy.1.0.ClassLibrary1.dll"
DiskId="1"
Source="..\ClassLibrary1\policy.1.0.ClassLibrary1.dll" >
</File>
<File
Id="LIBGACPolicyConfig"
Source="..\ClassLibrary1\policy.1.0.ClassLibrary1.config"
CompanionFile="LIBGACPolicy">
</File>
</Component>
</Directory>
When compiling with VS2008 appears this error:
policy.1.0.ClassLibrary1.dll appears to be invalid. Please ensure this is a valid assembly file and that the user has the appropriate access rights to this file. More information: HRESULT: 0x8013101b
And lastly, when compiling with VS2010 doesn´t appear to be any problem. But
at finalizing the installation process, the DLL is well installed and the
publisher policy didn´t. Also I read the log generated during the installation and I wasn´t able to find a cause.
Thanks for reading.
I've been doing something similar and works well using Visual Studio 2010 and in a Build Server with MsBuild:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="Gac" Name="Gac">
<!-- The component with the assembly -->
<Component Id="MiClassDLL" Guid="*">
<File Id="MiClass.dll" Assembly=".net" KeyPath="yes"
Source="$(var.MiClass.TargetPath)" />
</Component>
<!-- The component with the policy -->
<Component Id="PolicyMiClassDLL" Guid="{YOUR_GUID_HERE}">
<File Id="PolicyMiClass.dll" KeyPath="yes"
Source="$(var.MiClass.TargetDir)Policy.1.0.MiClass.dll" />
<File Id="PolicyMiClass.config" KeyPath="no"
Source="$(var.MiClass.ProjectDir)Policy.1.0.MiClass.config" />
</Component>
</Directory>
</Directory>
</Directory
In my case I have the policy.config file in the same project directory and I build the policy dll in the same output to make easier the installer script.
I noticed that the policy component must have a guid and for some reason it requires internally that policy dll and config files in the same directory/component.
I build the policy assembly in the Post-Build event of MiClass project with this command:
"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\al.exe"
/link:"$(ProjectDir)Policy.1.0.MiClass.config"
/out:"$(TargetDir)Policy.1.0.MiClass.dll"
/keyfile:"$(SolutionDir)MyKeys.snk"
/comp:"My Company"
/prod:"My Product"
/productv:1.0
/version:1.0.0.0
I hope this works for you.
I did some work with policy dlls, and the only difference I can see is that your file naming convention is a little different than ours was.
Instead of
policy.1.0.ClassLibrary1.dll
policy.1.0.ClassLibrary1.config
We used
policy.1.0.ClassLibrary1.dll
ClassLibrary1.dll.config
instead of /link switch use /embed to compile the xml-config into publisher policy. then you can install the resulting assembly into GAC without problems

Wix major upgrade; need different behaviors for different components [duplicate]

This question already has an answer here:
WiX custom action with DTF... quite confused
(1 answer)
Closed 2 years ago.
Okay! I have finally more closely identified the problem I'm having. In my installer, I was attempting to get a settings file to remain intact on a major upgrade. I finally got this to work with the suggestion to set
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallFinalize" />
</InstallExecuteSequence>
This is successful in forcing this component to leave the original, not replacing it if it exists:
<Component Id="Settings" Guid="A3513208-4F12-4496-B609-197812B4A953" NeverOverwrite="yes">
<File Id="settingsXml" KeyPath="yes" ShortName="SETTINGS.XML" Name="Settings.xml" DiskId="1" Source="\\fileserver\Release\Pathways\Dependencies\Settings\settings.xml" Vital="yes" />
</Component>
However, this is a problem. I have another component listed here:
<Component Id="Database" Guid="1D8756EF-FD6C-49BC-8400-299492E8C65D" KeyPath="yes">
<File Id="pathwaysMdf" Name="Pathways.mdf" DiskId="1" Source="\\fileserver\Shared\Databases\Pathways\SystemDBs\Pathways.mdf" Vital="yes"/>
<File Id="pathwaysLdf" Name="Pathways_log.ldf" DiskId="1" Source="\\fileserver\Shared\Databases\Pathways\SystemDBs\Pathways.ldf" Vital="yes"/>
</Component>
And this component must be replaced on a major upgrade. I can only accomplish this so far by setting
<RemoveExistingProducts After="InstallInitialize" />
This breaks the first functionality I need with the settings file. How can I do both?
The problem is that settings.xml shouldn't be installed in the first place, what you really want to do is install something like a 'defaultSettings.xml' and have user-editable settings in a separate location, copying the default to the user/system config in either a post-install configuration step or at first run. If the user modifies the file, and runs a "repair" then it's going to get overwritten anyway, this is the intended behavior of Windows Installer.
If you really want Windows Installer to "leave the file alone" then you're going to need an unmanaged component, i.e. a component with an empty GUID. Such as...
<Component Id="Settings" Guid="" NeverOverwrite="yes">
<File Id="settingsXml" KeyPath="yes" ShortName="SETTINGS.XML" Name="Settings.xml" DiskId="1" Source="\\fileserver\Release\Pathways\Dependencies\Settings\settings.xml" Vital="yes" />
</Component>