WIX: Files not copied over on new installs - wix

So, I have a WIX project which is to install either fresh installations or over previous installations of a product. This product, if it was already installed, has several files inside of 3 different folders which need to be preserved. This project also needs to copy the contents of those 3 different folders into another set of folders (same content in two different locations). In order to accomplish this I have set up my project to first attempt to write into the original folders if the files don't already exist, then copy the contents of those folders. On an upgrade where those files already exist this works fine. On a fresh install the second set of folders do not get created, but all the files do.
My assumption, and I may be incorrect, is that the msi is attempting to copy the folders over before they have even been created. This would cause folders to not exist in the area they were supposed to be copied to as there would be nothing to copy from. Is there a way I can ensure the files have been generated before trying to copy them? Is there a better way of going about this that I'm not seeing?
EDIT:
I'm going to try to clear this up a little. What I'm trying to do is the following (pseudo):
1) See if an option file (hi.opt) exists in c:\options, if not create it.
2) Copy that file to c:\options\opt2015.
I'm doing this 3 times for 3 different folders. I am creating the initial files with Wix in the c:\options folder using the NeverOverwrite parameter. This part works great; the files are created without issue and none are overwritten if they already exist. Where the problem lies is step two where I'm using the CopyFile Wix command. This will only copy some of the files from the c:\options folder to the c:\options\opt2015 folder. Depending on the initial setup of the system (if the files at c:\options exist or not) some files will copy over and others won't. It's not random, the results are repeatable every time, but there seems to be no reason why some files copy and others don't depending on the initial setup of the system.
I hope this makes sense and is a little more clear, though I think it makes things worse! It is strange behavior because to me it looks like everything should just work, but it doesn't (isn't that every bug though).
Edit2:
After more work and creating a vb script which runs perfectly outside of WIX my team and I have determined that the files just are not being seen by WIX during the installation even though they do exist. We haven't found any permissions issues and the installation is running as admin on an admin account. Doing the copy via a VBS or through the Wix CopyFile command results in, well the same results; files that already exist on the system are not being copied. Any more ideas? Should we find a solution I'll be sure to post it because this is just getting weird.

I believe your installer design should work as long as you're attempting to copy the files after the InstallFiles action runs. You should be copying the files from the first set of folders to the second set of folders by doing one of the following:
Running a deferred custom action that executes after InstallFiles
Using the MoveFiles action

This is too long for a comment, but may not be an answer either....
There isn't really such a thing as "over previous installations of a product", especially if you end up with multiple instances in Programs/Features, and files that may or may not have the same component ids replacing each other - that's going to be a mess. If you need to upgrade the installed product, use a major upgrade, that seems to be where you're going with this. If you are already writing custom actions to do some of this "first attempt to write into the original folders" then I've no idea what's going on or where you doing this in the install. In general, if you need those files in the new install then add them to the new major upgrade MSI. If you need to copy the older existing files from the older product, then do a major upgrade with afterInstallExecute and write custom action code to copy them before the InstallFiles action. Or the CopyFile WiX element could do it, see the part about the element under a component with no fileid.
http://wixtoolset.org/documentation/manual/v3/xsd/wix/copyfile.html

Well, as sometimes happens, the error was entirely elsewhere. It turns out that an uninstaller for another program which was in the chain of programs which are installed at the same time was destroying the folder. Unfortunately this is what happens when a product isn't touched for 10 years. Thank you for your contributions, they were very helpful. Even though I was going down the wrong path the whole time I still made use of them in my tests and am more adamant about checking the installation order.

Related

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.

Remove or rename files during minor update(wix 3.9 patch)

We’re generating setups automatically every week, in order to fix bugs or introduce new features to our product.
All the components are being harvest automatically in the Wix Library(ies) pre build step(s).
eg:
"%WIX%bin\Heat.exe" project "%SolutionDir%projectNameXXX.Web\projectNameXXX.Web.csproj" -configuration %FlavorToBuild% -directoryid dirBE9FDAE56D974104BBF8070FB6CC7F69 -platform AnyCPU -pog Content -projectname projectNameXXX.Web -ag -sfrag -out "%ProjectDir%projectNameXXX.Web.wxs"
So, there is a component with a “*” Guid for every file we’re deploying.
We’ve automatized also the patch creation between any previous version of our setup (let’s say V0) and the current version (V1). The patch gets created, and is being deployed, as long as no file is being removed(or renamed) by V1. We don’t mind if the files from V0 don’t get deleted, as long as updated files and new files get deployed.
So far I’ve done dozens of tests, with different parameters for example:
adding –sfdvital on candle in order force the files not to be vital, but I finally figured out that the problem comes from the components, not the files…;
another significant test was setting hard coded Guids on 3 Components in V0, that I remove in the V1 setup. The generated patch gets installed (the to be deleted files are still on the disk, all the other files updates get deployed). When the setup gets uninstalled, everything is removed except for the 3 files. Unfortunately, if the setup V1 removes the 3 files but adds 1 other file, the patch doesn’t get installed, it stops as soon as it encounters the first to be removed file.
SELMGR: ComponentId '{68FB7BC2-8D59-4CFB-88F5-9AA8CA570345}' is registered to feature 'ProductFeature', but is not present in the Component table. Removal of components from a feature is not supported!
The related topic :
Remove file during minor upgrade
is not presenting a viable solution as I cannot apply the “puncture pattern” technique, or add tags as this cannot be done automatically. Or can it?
If a user has to edit the V0 msi, get the components ids and add them to the new msi or patch, this is not a solution for us. We’re deploying over 25000 files. A major upgrade is not a solution either.
Any idea would be welcomed!
You can't delete the component, but you can matk it transient and associate it with a property with a false value so that the file is not actually on the system. The component is still there but the file will be gone. The same should work if you want to rename a file. As above, arrange for the file to be absent and add the renamed file as a new component to an existing feature.
Minor updates are really used for fixing existing resources, not adding, renaming or removing them, which is why the safest solution is a major upgrade.
We have finally managed to generate minor update patches that are successfully installed.
Here is what we have done:
We have our SetupV0.msi
In the PreBuildEvent of our wix setup project we run dark.exe on the SetupV0.msi, e.g:
"%WIX%bin\dark.exe" "%OldSetupDir%SetupV0.msi" "%OldSetupDir%SetupV0.wxs"
A wxs file gets generated.
Then we call a console app that reads all the component GUIDs and ids from the resulting wxs and, for each one of them, tries to find a match in all the wxs libraries that are in our workspace. We recover all the GUIDs and ids that don’t have a match and we generate a wxs file with empty components (that have bogus registry keys as children) and component refs. This generated wxs is already included in the setup project.
Then the build happens and a SetupV1.msi gets generated. This setup contains all the component ids and GUIDs of the V0 and possibly some new files.
Then, in the PostBuild event we create the msp.
Maybe it is not the neatest solution, (not very proud of the registry keys), we’ve tried to add empty createfolder tags, but the create folder tags made the patch uninstallable.

Cleaning up duplicate entries in a Wix installer

I need some advice about how to clean up an old Wix project that hasn't been managed very well. One problem is that the project currently has multiple entries for the same files, going to the same location. For example, several .wxs files in the project will define a new component for foo.exe, each using a different GUID and each sending this file to the same DirectoryRef. This hasn't yet created any issues, but now I want to use patches (MSPs) in our product and this sort of thing messes with their operation.
I'm wondering about the best way to resolve this without breaking upgrades (since all previous installers have gone out like this). If I simply remove all the duplicate components, we get undefined behavior during an upgrade. I think what's happening is that removing one or more duplicate entries will cause the installer to generate delete operations for that file. Even if the remaining entry for the file is a new version, there is no guarantee in the order of operations during the install. So some of these files will first get updated, then one or more delete operations will remove the updated file. Thus at the end of the upgrade several files will be missing. Running a repair immediately afterwards will restore the files, since the installer knows they are supposed to be there.
I imagine one way to resolve this is to do a one off "hack" in our next release, where we copy these files into a secondary location, then run a custom action post install that copies the files from the secondary location into the primary and delete the temporary directory.
Is there a cleaner way this could be resolved?
What you are likely going to have to do is use validation to identify all the duplicates and fix them. Then change your upgrade to be a major upgrade with the earliest possible scheduling. You may also have to change your install location to a slightly different directory to get around component reference counts breaking.
Once clean you should be able to go back to minor upgrades and start thinking about patching. An alternative would be "fake" patches. I've used an MSI that doesn't publish itself as a hotfix method very successfully. It breaks a lot of rules but can be useful for organizations that don't care about patching rules and just want to make the business happy.

How to copy a folder (not a file) during installation with WiX?

I'm writing an installation code using Wix, and I need to install an entire folder to a certain location, and then copy that folder to several different locations, I could install those same files to those locations using code one by one, but that folder is about 80 Mb in size, so it would increase my MSI size (80 x 3 = 240 Mb).
One solutions I had thought of was compressing the folder into a zip file, and then use the CopyFile element to copy the file, after that, descompress the three folders, but this increases the installation time too much.
Is there a way to do this using native wix code, or is Custom Actions my only solution?
Tnks
WiX's "smart cabbing" reuses one instance of a file's stored data even if it's included multiple times in different directories. See http://robmensching.com/blog/posts/2007/6/1/quotSmart-cabbingquot-added-to-WiX-toolset. So you have duplicate authoring but without bloating the .msi.
If you want to do it the way that MSI natively provides, you need to author 3 CopyFile elements for every single file that you want duplicated.
The CopyFile element maps to the DuplicateFile table which is processed by the DuplicateFiles action. It has no concept of */ rather it requires a 1 to 1 mapping back to the File.File_ table/column. ( File#Id in WiX )
You certainly could decide that you hate this pattern and roll your own custom actions to handle the job but if you do, make sure you handle install, uninstall, repair, rollback, upgrades and so on. MSI's restrictions can be annoying but you do get a lot for 'free' (albeit not painless) if you use it.
CopyFile Element
DuplicateFile Table

How can my WiX uninstall restore a registry value change?

The installer I'm writing using WiX 3.0 uses a RegistryValue element to modify an existing registry value (originally written by our main product). I'm trying to figure out a way to restore the registry value when the user uninstalls my utility. I'd like to avoid using a custom action, but that might be the only recourse? TIA.
I did this. The registry value in question was the application associated to a file extension, but it could be any registry value.
My first idea was to use a "custom action" for install and uninstall to preserve
and restore, respectively, the associated regy state. This
seemed simple enough.
I created a setup project in VS2008 and built the CA's as javascript files. The "on install" script grabbed the existing regy value and stashed it into a well-known place. The "on uninstall" script would look in the well-known place, and then put the value found there, back in the original location.
Easy, right?
There were two problems:
the script that ran during install, to preserve the pre-existing registry value,
runs AFTER the registry has already been updated
with the values for the newly installed thing. So it preserved the new setting instead of the setting that was there before the MSI ran. Not useful.
The script that runs during uninstall, runs AFTER the registry values, and in fact the entire directory subtree,
have been deleted. Including the stashed value. So it had lost its state.
To solve that I wrote another script that
re-orders the custom actions so they run at the proper times.
There's actually one more twist. Obviously, the "Restore" script (on
uninstall) won't work if it is run after the registry entries for the app have been deleted. I can't remember now, why... but I also determined that this script could not run before that. Somehow that wasn't working either.
So, I modified the MSI to run the restore script
twice. In phase 1, it transfers the stashed value to a "parking lot" in the registry.
Then the application's Keys and Values in the registry get deleted, but the parking lot remains. In
phase 2, outside the transactional protection, the restore script retrieves the state from the parking lot, restores
the file association, and then deletes the parking lot.
I can't remember exactly why I needed to do this in 2 steps, but I remember fighting with it for a while before coming up with that solution.
The way it works in development:
set the on install and on uninstall CA's in the VS project
build the VS Setup project
run the post-processing script that modifies the MSI.
When using the MSI, it's a little more complicated than I originally thought but it works.
If you are using WiX, you may have more control over the time and ordering of the steps, so may not need that post-processing step.
Finally, you said you wanted to avoid a CA. To me, CA's are avoided because they are painful to produce in C++, and producing them in .NET is often inappropriate. But, it's pretty simple to use Javascript for CA's. Some people think script is the wrong tool for the CA job. I think that's wrongheaded. I think script is a very good tool for this purpose. And once you can accept script as a good tool, then you don't need to hold your nose about creating a custom CA.
The registry table is incapable of writing a registry value during an uninstall so it is correct that this must be done via custom action. I am of the opinion that using script is bad. Whether you choose to listen is up to you. I can tell you that just the other day I was called into to trouble shoot a situation where some wrote a vbscript CA that was failing because the file system object had been unregistered as part of a security lockdown process.
I suggest C++ or C#/DTF depending on your needs.
Faced with similar issue, need to update the registry value on install and restore to previous value on uninstall.
Is the only solution possible is creating a custom action for this purpose?
I found a extension for wix that has fucntions for this purpose
link to wix extensions