How to find whether the MSI has InstanceTransforms enabled or not? - wix

We have an WPF based external UI application i.e setup.exe which wraps the msi's developed in WiX. We have a requirement that some components/msi's requires multiple instance support and some don't require multiple instance support but all components are part of single package.
We pre-defined InstanceID's, ProductCode and UpdgradeCode for each instances during build time. Because creating instance ID on the fly create complexity in the patch/upgrade scenarios.
We want Setup.exe to do 2 things,
1. It should lookup the target computer and detect if any component is installed already. To do that Product code required.
2. It should automatically detect the msi's copied into the path and lookup the InstanceTransforms exist or not in the msi. If InstanceTransforms found then it should fetch the Instance ID's defined. Because we don't want to keep any business logic in Setup.exe. Reason is to avoid recompile Setup.exe every time we change the msi.
Now Setup.exe will know whether the msi requires instance ID or not based on that it will invoke the msi and pass commandline parameters. It's kind of plugin mechanism to avoid regression.
Issue:
We could not retrieve the InstanceTransforms from MSI maybe because it's not a property. We have checked the _Storages table and property table but we could not figure it out.
How can we retrieve the InstanceTransforms element and it's Instance definition (InstanceID and ProductCode) in the msi?
Please advise.
#Christopher Painter

I don't follow your question exactly. In general you can use the WiX DTF Microsoft.Deployment.WindowsInstaller library to do queries against the MSI database and MSI API. You can query the Property table to get the ProductCode then query installed products to see if it's installed. To see if the MSI has embedded transforms available you can query the _Storages stream, apply the transform and then read the properties for those also.
I'm adept at WPF/MVVM development if you want to hit me up for more detailed consulting.

Related

WiX - Dynamically changing name of installed product in Add/Remove Programs

I am working on an installer with WiX which takes a "name" input from the user using a textbox in a dialog. This name will be used to name the product that i am installing.
But, i am not able to set the product name dynamically during install. Even if i use a custom action, the registry entry is getting created with the static name that i have provided earlier. This is ultimately leading to inconsistency.
Can anyone please help me regarding this?
This cannot be done in a custom action. It's true that you can set the ProductName property in a custom action (such as a type 51) early in the install and that will indeed change the name in the UI, but it will NOT change the name of the installed product - it will remain the same as the original value. For example, enumerating installed products will return the original name.
So the only good way to do this is to modify the ProductName in the MSI file before you launch it. You would have a launching program that modifies the MSI file and then installs it. The MSI file is a database that can be modified in the Property table to change the value of ProductName. This example will give you the general idea:
How do I add/update a property inside an MSI from the command-line?
but basically you open the open the database (MsiOpenDatabase or equivalent) then MsiOpenView with a SQL such as:
"UPDATE Property SET Property.Value = 'Your variable' WHERE Property.Property = 'CurrentProductName' "
then MsiViewExecute and close handles etc. Details depend on your preferred coding language environment.
This is not an ideal solution because if your MSI file is digitally signed you have tampered with it and it is no longer correct.
Another way is to generate a transform file, based on altering a copy of the MSI file. If you make a copy of the MSI file, and then do the alteration of ProductName as above you can then do an MsiDatabaseGenerateTransform() call which will generate a transform file, a .mst file, the difference between the two MSI files. You then install the original unaltered MSI file with a command line that includes TRANSFORMS=[the .mst file] which will update the ProductName and start the install.
None of this is very easy because Windows Installer products are not designed to have dynamic product names. Maybe historically and before Windows Installer setups this was more practical, but not in MSI setups.

How we can store values of variables across Bootstrapper and MSIs getting called from that Bootstrapper

I have created a Wix Installer which has following structure
It has Bootstrapper
It has MSI1
It has MSI2
The task of Bootstrapper is to provide options to user as which
application he wants to install. Based on his selection MSI1 or MSI2
will be launched.
Now both MSIs need to collect information of Database.
My requirement is that if I collect DB information from MSI1, I want to pass that information to MSI2 from Bootstrapper(as after MSI1 user will choose MSI2 from Bootstrapper)
We don't want the end user to provide this database information again and again.
Please note that we cannot collect the database information from Bootstrapper itself, as the user may go to installer source and execute MSI1 or MSI2 directly.
Any one has idea how we can store values of variables across Bootstrapper and MSIs getting called from that Bootstrapper?
Write that information to a well-known registry location during the installation.
Here's a resource to the "remember me pattern" blog post that Rob has written. I know it's bad practice to just link a blog post that may not exist in the future but I also don't want to just copy most of it.
The basic idea is to save properties that may be defined by the user at run-time into the registry. When you run the installer again, you can try to read that registry location and load up the properties from a previous run of the installer so you already know what the user is going to write.
In this case, your 2nd installer will know about the well know registry location that the first installer will write the db information to. Now the 2nd installer can read this information when it is run afterwards and use it during hte installation which means the customer doesn't have to re-enter the same information for both installs.
You can combine this with custom actions to encode sensitive information and decode it at run time. This is also a very commonly used technique for remembering the install directory of a product as this is something that is commonly changed by the user at run-time.
I reread the question and realized that getting the information from the bootstrapper is not something you can do but I'll leave this part of my answer here anyways. [I think you could gather the information in the bootstrapper and pass it to the MSIs. Just write that information during the install to a registry location and you can read it if it exists when installing if the user runs just from the MSI]
Alternatively you can update your bootstrapper's UI to gather this information and pass it in to both installers. This requires a bit of research into how the bootstrapper application works and how it generates its UI and stores properties. And again, you should use the remember me technique to read the already entered properties from the registry if they exist so you can pre-populate fields with the previous values on subsequent runs of your installation.

How to use CustomAction in WIX Bundle?

To give you a background - I have a 4 MSI's which comes from our vendor and this has to go to our company servers (we are looking at around 3500 servers). As of now, my counterparts are managing this using vbs, ps1 scripts. But the problem with the script is that everytime an update comes we have to worry about uninstalling the existing package before running the new one and a ton of hardcoding.
I want to automate the whole process (with very less hardcoding) by setting up a WIX script to package all the 4 MSI's together. I read about the WIX bundle and used that to create a single MSI. But now there are lot of a variables to be passed to the 4 MSI's, so I thought of using custom actions to set these variables based on the environment/machine where the MSI is running. But I cant make custom action to work? Am i missing something?
A little bit of googling and I saw something like there are no CustomActions in Bundle? can someone confirm?
Also if there are no CA's what are my options? how can I manipulate the variables to be passed on to the 4 MSI's? Most of them needs to be set based on the machine its being run (like install path, user id's, app pool id's etc).
There is a fourth option, a useful lightweight hack, identified by Vijay Kotecha (see http://vijayskotecha.blogspot.com/2013/07/wix-bootstrapper-custom-action.html),...
Essentially, build an <ExePackage> around a pass-through .bat or .cmd batch file. The batch/command file contains the single line '%*' which re-executes all of the command line arguments as a first class command.
Thus:
<ExePackage ... SourceFile="SourcePath\WixCustomAction.cmd"
InstallCommand="my_custom_action.exe my_custom_parameters" />
<ExePackage ... SourceFile="SourcePath\WixCustomAction.cmd"
InstallCommand="my_next_action.exe my_next_parameters" />
Where WixCustomAction.cmd is a file containing only '%*'.
These <ExePackages> can be placed into the <Bundle><Chain> successively as needed using different InstallCommands as needed.
As I see it, you have three options:
Depending on what information you need, you can use the WixUtilExtension to perform simple tasks such as reading registry keys and performing file searches, which you can then pass the results to your installation packages as properties.
Implement custom actions in the individual installation packages themselves (not in the bundle).
Write your own custom bootstrapper application to determine all the properties you need to set, and then pass them to your installation packages. This is more complex than the #1 and #2, but if your interested the following links should get you started:
introducing managed bootstrapper applications and
write a wpf wix installer

Wix: Dynamically Add Features

We are using Wix to build msi for our software. We have some components (plugins) to be implemented to the target machine. The plugins are different from one client to another. What we want to be able to do is to create a standard build and modify the feature list in the msi package. Is there a way to change the feature list dynamically from a custom action? (e.g. read the available plugins from a custom action and add some entries into the msi feature list accordingly)?
Any comments, advice, ideas are very much appreciated.
I've done a trick in the past where you build the MSI with external CABs ( 1 per feature ) and then use a custom action to verify that the CABs exist. If they don't exist you hide the feature. This way you can just build the installer once but then ship it to customers with different feature sets.
BTW, InstallAware has supports this story natively I believe.

MSI/WiX - Assigning Component GUID's during Multiple Instance Transforms

Using WiX 3.5, I have an MSI with instance transforms allowing me to install the software on the same machine with different product names. To do this, I have a "hard-coded" list of product id's and names in the .wxs file defined conditionally. However, I have only the single Feature-ComponentRef definition that includes both file and non-file resources.
Installation appears to work fine, but uninstalling the instances demonstrates the behaviour mentioned in these two sources:
http://msdn.microsoft.com/en-us/library/aa367797(v=VS.85).aspx
and
http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/Multiple-Instance-Transforms-Walkthrough-Proposed-Simple-Addition-to-WiX-to-Make-Them-Easier-td708828.html
Specifically, none of the non-file resources (in this case, registry entries) get uninstalled save the very last instance of my application. (i.e., if I uninstall in this order: instance1, instance2, and instance3 - only instance3's non-file resources are removed.
I am presuming this is related to not having unique GUID's for nonfile components (whereas this isn't an issue for file components)
So, I was wondering whether a valid approach would be to define a single .wxs file with one product id, name and one set of features, but have a custom bootstrapper generate new GUID's for the product and non-file components which then get inserted into the MSI database at runtime? i.e., Then when it comes time to uninstall or update, I would query the registry for installed instances and retrieve their GUIDs then.
This would permit instances to be created at runtime rather than hardcoded in the .wxs in advance, and to be uninstalled cleanly.
Does that make sense? Will Burn make everything better? :)
As of version v3.6.1511.0, there is now a "MultiInstance" attribute for components. This allows a guid to be generated on the fly for each instance as per Josh Rowes suggestion in his post to the WiX mailing list (see the link in the OP). I have tested and this works correctly to cause registry data to be removed when the current instance is uninstalled, and not when the LAST instance is uninstalled.
You don't need to have unique component ID's but you do need to have unique registry keys. Check out:
Authoring Multiple Instances with Instance Transforms
The article mentions:
To keep the nonfile data of each
instance isolated, the base package
should collect nonfile data into sets
of components for each instance. The
appropriate components should then be
installed based on conditional
statements that depend on the instance
identifier.
I actually don't know what they are talking about there. I created n-Tier multiple instance installers where all the files were isolated by unique INSTALLDIR ( type 51 custom action at runtime to mutate the destination based on the InstanceID ) and all the registry data was mutated using the InstanceID as part of the path as mentioned in the article. I supported up to Sixteen unique instances with unique configuration data and unique version #'s ( each instance could be serviced via major upgrade apart from the other instances. ) All of this was to support a SaaS deployment model for an nTier application and I never ever had to create components with unique GUIDS and/or Conditional expressions.
The only thing wonky I had to do was on the client side they wanted a Shortcut on the desktop. (The Client supported multiple instances also because a site might have v1.0 in Production and v1.1 in Test )
Because I couldn't mutate the folder name (fixed) and because MSI's ShortCut table doesn't support formattable, I had to write a custom action to author the ShortCut dynamically at install table using the InstanceID into a TEMP table and then MSI created the shortcut for me.