Single MSI --> Multiple products
I've been asked to take a look at cleaning up our build and deployment process for a couple of .NET web apps. We need to be able to install multiple copies of the exact same code, each as a distinct product. So on one server we might have something like this:
Test Version for Customer A
QA Version for Customer A
Test Version for Customer B
QA Version for Customer B
... etc.
Currently this is done by maintaining one Visual Studio deployment project each for every possible incarnation of the product, each with its own virtual directory as the TARGETDIR. This works but is a maintenance mess; multiple deployment projects have to be updated if a change is made, and this scheme lends itself to creating inconsistent version numbers across deployment packages.
Ideally the goal is to build a single base MSI from a single deployment project, then use scripts to make as many copies of that as necessary and customize each one. I'm trying to do this using the VBS scripts that come with MS platform SDK. So for example I'll generate "original.msi", make a copy to "newapp.msi", and try the following to change the ProductCode, ProductName, PackageCode, and target virtual dir.
cscript WiRunSQL.vbs newapp.msi "UPDATE Property SET Value='{replacement GUID here}' WHERE Property='ProductCode'"
cscript WiRunSQL.vbs newapp.msi "UPDATE Property SET Value='Not the same product' WHERE Property='ProductName'"
cscript WiSumInf.vbs newapp.msi 9={another replacement GUID}
cscript WiRunSQL.vbs newapp.msi "UPDATE CustomAction SET Target='New Virtual Dir' WHERE Source='TARGETVDIR'"
This method successfully makes the above changes, and based on my (admittedly rather limited) knowledge of MSIs, I believe that the distinct ProductCode and PackageCode should be enough that Windows will recognize the applications installed by original.msi and newapp.msi as distinct... but it doesn't work.
If newapp.msi is run after original.msi (or vice-versa), I get "Unable to install because a newer version of this product is already installed" as if the PackageCode hadn't been changed. Is there something I'm missing here?
Test Version for Customer A
QA Version for Customer A
Test Version for Customer B
QA Version for Customer B
... etc.
Currently this is done by maintaining one Visual Studio deployment project each for every possible incarnation of the product, each with its own virtual directory as the TARGETDIR. This works but is a maintenance mess; multiple deployment projects have to be updated if a change is made, and this scheme lends itself to creating inconsistent version numbers across deployment packages.
Ideally the goal is to build a single base MSI from a single deployment project, then use scripts to make as many copies of that as necessary and customize each one. I'm trying to do this using the VBS scripts that come with MS platform SDK. So for example I'll generate "original.msi", make a copy to "newapp.msi", and try the following to change the ProductCode, ProductName, PackageCode, and target virtual dir.
cscript WiRunSQL.vbs newapp.msi "UPDATE Property SET Value='Not the same product' WHERE Property='ProductName'"
cscript WiSumInf.vbs newapp.msi 9={another replacement GUID}
cscript WiRunSQL.vbs newapp.msi "UPDATE CustomAction SET Target='New Virtual Dir' WHERE Source='TARGETVDIR'"
This method successfully makes the above changes, and based on my (admittedly rather limited) knowledge of MSIs, I believe that the distinct ProductCode and PackageCode should be enough that Windows will recognize the applications installed by original.msi and newapp.msi as distinct... but it doesn't work.
If newapp.msi is run after original.msi (or vice-versa), I get "Unable to install because a newer version of this product is already installed" as if the PackageCode hadn't been changed. Is there something I'm missing here?
0 Comments
[ + ] Show comments
Answers (7)
Please log in to answer
Posted by:
drl2
14 years ago
ORIGINAL: pjgeutjens
basically what this check does is make sure that you don't install say, version 4.0.0 of your application over version 5.0.0. There are a number of actions you can take here, ranging from reasonably elegant to rather crude...
I'm still not sure why UpgradeCode issues would cause the Already Installed issue when ProductCode and PackageCode are different between the different MSIs. When I copy an MSI and try to turn it into a different product, do I also need to specify a new UpgradeCode (common, I'm assuming, to all non-major releases of the "new" product) and plug that code into the Upgrade table? I want the actual version number to be consistent across all products for a given build of the base code.
(Also, I seem to be unable to update the Upgrade table with WiRunSQL.vbs. I just get an 80004005 error.)
Posted by:
pjgeutjens
14 years ago
Unable to install because a newer version of this product is already installed
This to me looks like the work of the Downgrade Prevention checks that often get built into msi's.
Have a look at your MSI's Upgrade table, make sure there's no check being done on an (I assume still identical) UpgradeCode for your packages.
PJ
Posted by:
drl2
14 years ago
Posted by:
pjgeutjens
14 years ago
There's a NEWERPRODUCTFOUND line in Upgrade - should I just delete it? What are the repercussions of this?
basically what this check does is make sure that you don't install say, version 4.0.0 of your application over version 5.0.0. There are a number of actions you can take here, ranging from reasonably elegant to rather crude...
1) you can modify the version range that the installer checks for in this check. Rather than explain this in detail I'm going to refer you to the Windows Installer Help files (or basically "Upgrade Table" when searched in Google). Have a look at the attributes column, VersionMinInclusive etc...
2) Change the upgrade code for your packages too, this will however "sever" the last link they had identifying your packages as being related
3) If you must, delete the entry in the Upgrade table, but remember there's a reason for 1) and 2) [;)]
Hope this helps
PJ
Posted by:
jmcfadyen
14 years ago
this is probably a more appropriate method to handle this
http://msdn.microsoft.com/en-us/library/aa369528(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa369528(VS.85).aspx
Posted by:
pjgeutjens
14 years ago
Posted by:
drl2
14 years ago
I created a transform with a different product name, product code, and target directory, used MSIexec to apply it as specified on the MSDN page referenced above... and got the same 'Already installed' error. I'm using insted to build the transform, and it doesn't let me edit the summary info in a transform for some reason. Do I need to provide new package & upgrade codes as well? Assuming I can get this method working, would a transform created for one build of a product work against future builds or is it tied to a specific base MSI file (i.e. would I need to build new transforms on a regular basis)?
I was able to modify an MSI for a second instance via the platform SDK using the following method, given a set of GUIDs that are assigned specifically to the "new product" for its lifetime (with the possible exception of PackageCode changes for major version releases):
- Copy base MSI to newapp.msi
- Change the product code, product name, target virtual directory, upgrade code
- Retrieve the current row from the Upgrade table where ActionProperty = NEWERPRODUCTFOUND
- Drop the row from Upgrade
- Insert a new NEWERPRODUCTFOUND row into Upgrade using the values retrieved from the old, substituting the new UpgradeCode from above
- Change the package code
If my massive day and a half of MSI experience isn't leading me astray, this scheme should work to create however many instances I need of a single installer, built from a single VS deployment project in any version of Visual Studio (we have some 2003 code to maintain), while maintaining consistent version numbers across products. I can even set it up so the list of products & GUIDs is maintained in a single CSV or XML file and a single script will loop through that and generate all the needed installers.
I was able to modify an MSI for a second instance via the platform SDK using the following method, given a set of GUIDs that are assigned specifically to the "new product" for its lifetime (with the possible exception of PackageCode changes for major version releases):
- Copy base MSI to newapp.msi
- Change the product code, product name, target virtual directory, upgrade code
- Retrieve the current row from the Upgrade table where ActionProperty = NEWERPRODUCTFOUND
- Drop the row from Upgrade
- Insert a new NEWERPRODUCTFOUND row into Upgrade using the values retrieved from the old, substituting the new UpgradeCode from above
- Change the package code
If my massive day and a half of MSI experience isn't leading me astray, this scheme should work to create however many instances I need of a single installer, built from a single VS deployment project in any version of Visual Studio (we have some 2003 code to maintain), while maintaining consistent version numbers across products. I can even set it up so the list of products & GUIDs is maintained in a single CSV or XML file and a single script will loop through that and generate all the needed installers.
Rating comments in this legacy AppDeploy message board thread won't reorder them,
so that the conversation will remain readable.
so that the conversation will remain readable.