Showing posts with label Installer Patches. Show all posts
Showing posts with label Installer Patches. Show all posts

Thursday, March 20, 2014

Signing problem with Wix based Bootstrapper.

I faced a problem very similar to defined here,  i.e. Whenever I signed the Bootstrapper, it failed to do the installation with following errors in log:

[1604:24F8][2013-12-04T11:50:00]e000: Error 0x80004005: Failed to extract all files from container.
[1604:2FB4][2013-12-04T11:50:00]e000: Error 0x80004005: Failed to wait for operation complete.
[1604:2FB4][2013-12-04T11:50:00]e000: Error 0x80004005: Failed to open container.
[1604:2FB4][2013-12-04T11:50:00]e000: Error 0x80004005: Failed to open container: WixAttachedContainer.
[1604:2FB4][2013-12-04T11:50:00]e312: Failed to extract payloads from container: WixAttachedContainer to working path: C:\Users\.....\{6ab8eece-89c6-4417-905f-6d9c5136519d}\C7C1FB4E513C19E0F5E8F6856FF2ACC4D7D143A2, error: 0x80004005.
[1604:2574][2013-12-04T11:50:00]e000: Error 0x80004005: Failed while caching, aborting execution.

Using solution defined there, and some guidance from WixToolset insignia page , I'm just summarizing the procedure here:


While building the msi:

  • If you are building separate cab files, then first sign the cab files and do Insignia -im MySetup.msi. Insignia will update your MSI with the digital signature information of its associated external cabs. The file will be updated in-place. Then sign your MSI.
  • If its only one MSI, then simply sign the MSI.

Signing Bootstrapper:

Bootstrapper actually  contains Engine.exe inside and if this is not signed with same certificate, then after you sign your Bootstrapper.exe, it would fail to install and you may have to face problem defined in the beginning of this post, even if your MSI is properly signed.

To solve this, before signing Bootstrapper.exe, using Insignia.exe, do following:

  1. First extract your Engine.exe from your Bootstrapper.exe: insignia -ib Bootstrapper.exe -o Engine.exe
  2. Now sign Engine.exe and put it back to Bootstrapper.exe, and then you can sign the Bootstrapper_Signed.exe.
However if you don't sign this, it would still work. Whenever windows would sense the execution of your Engine.exe, it would show a dialog with signing information.But if you try to execute unsigned Bootstrapper_Signed.exe as Administrator, it would show "Unknown Publisher". That's why it is recommended to sign Bootstrapper_Signed.exe as well.


Thursday, October 11, 2012

How to generate a GUID at command line in Windows?

Well, like me who works with WIX and have to deal with lots of GUIDs, you might come across a situation where you may need to generate a GUID at command prompt during a procedure. I faced this while working with WIX based patches and unfortunately, like in other WIX templates i.e. Product, Module, PatchCreation doesn’t support Id=”*” where at the place of *, WIX compiler generates a new GUID each time.

So had to search for a command line utility in order to generate GUID randomly. Actually you can program such things even in VBScript and JScript, but I was looking for some built-in thing, to avoid adding new application to our build machine.

And I found UUIDGEN.exe. Yes, I know, Ancient C programmers are very much aware of this, but I only heard about it onceSmile with tongue out

It comes with almost every Visual Studio and with Windows SDK Tool. On my machine, it was present at following locations:
C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\Uuidgen.Exe

C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\uuidgen.exe

And here is its command line help:

"C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\uuidgen.exe" /?
Microsoft UUID Generator v1
.01 Copyright (c) Microsoft Corporation. All rights reserved
usage: uuidgen [-xisconvh]
x - Generate sequential
(V1) UUIDs
i - Output UUID in an IDL interface template
s - Output UUID as an initialized C struct
c - Output UUID in upper case
o
<filename> - redirect output to a file, specified immediately after o
n
<number> - Number of UUIDs to generate, specified immediately after n
v - display version information about uuidgen
h
,? - Display command option summary


In older versions of UUIDGEN.exe you might not getting option "-c" i.e. output upper case. So to generate a quick GUID, simply issue:
”C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\uuidgen.exe”


and you’ll get something like this:
5fae2556-299f-44dc-af2a-9afa3948e8a2 


and if you need Upper case issue same command by adding –c i.e.


“C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\uuidgen.exe” -c


and you should one in upper case:
2C4E4CD9-4635-42B6-A88A-099E952B95E8 .


 


How to use UUIDGEN in bat/cmd scripts?


Microsoft has provided “For” command which can be used to run any other command, read files  etc etc and then further process their outputs. Here is how you can use For with UUIDGEN to save generated GUID into an environment variable:

for /f %i in ('UUIDGEN') do set aGUID=%i


and this would define an environment variable aGUID containing your generated GUID.


 


 

Wednesday, August 1, 2012

Using NSIS to launch msp installation.

Today, I got a task to deliver a msp file (Windows Installer Patch) to the user machine. To install *.msp files, we usually have to issue following command line:

msiexec /p “<msp file name with path>” REINSTALLMODE=oums REINSTALL=ALL /qr

For more details, see this article

And it seems odd to ask user to issue that log, horrible command line. So either, either I have to provide my user with a .bat/.cmd file containing above command line, or a self extractive archive containing the Patch and its command line. 

The best convenient method I found for my user is some self extractive archive and I quickly choose NSIS ((Nullsoft Scriptable Install System).

Plan was simple:

  1. Deliver *.msp file to a Temp folder
  2. Launch Patch installation with above command line and log the installation
  3. NSIS installer should not show the details of installation.
  4. Remove *.msp File but leave the Log file thereat the End of Patch installation
  5. Auto-Close the NSIS Window.

So making long story short, here is that NSIS script. Smile

NSIS Code to launch msp installation
  1. !define PRODUCT_NAME "Patch for build 225"
  2. !define PRODUCT_VERSION "8.11.9.357"
  3. !define PRODUCT_PUBLISHER "My Company, Inc."
  4. !define PRODUCT_WEB_SITE "http://www.google.com"
  5. Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
  6. OutFile "Patch for build 225.exe"
  7. InstallDir "$TEMP"
  8. Icon "Bentley.ico"
  9. SilentInstall normal
  10. ;//This will make installer not to show the details
  11. ShowInstDetails nevershow
  12. Section "MainSection" SEC01
  13.    ;//This will close the NSIS Installer Window at end.
  14.    SetAutoClose true
  15.    SetOutPath "$TEMP\PATCH_225_357"
  16.    SetOverwrite ifnewer
  17.     File "PATCH_225_357.msp"
  18. SectionEnd
  19. Section -Post 
  20.     ExecWait '"msiexec.exe" /p "$TEMP\PATCH_225_357\PATCH_225_357.msp" REINSTALLMODE=oums REINSTALL=ALL /qr /l*v "$TEMP\PATCH_225_357\PATCH_225_357.log"'
  21.     Delete /REBOOTOK "$TEMP\PATCH_225_357\PATCH_225_357.msp"
  22. SectionEnd

 

Friday, July 27, 2012

MSP ERROR - Internal PatchWiz Error 1627.

I was building a patch based on Patch Creation Properties (pcp) method. In my build procedure, MsiMsp.exe v4.0 (part of Windows SDK 6.0) was used to compile .pcp file. I faced error 1627 and here is it from build log:
ERROR: Failed to execute a view
ERROR: The Last Error Received is: 1627
Then I tried MsiMsp.exe v 5.0 (part of Windows SDK 7.0) and this time error description got little change:
ERROR: Internal PatchWiz Error occurred. (Media, Duplicate DiskID likely)
ERROR: The Last Error Received is: 0x65b (1627)
Well, I was bit confused what's going on, because I was following Msdn tutorial for creating pcp files, and was not expecting any problems with it.
Thanks to
Huck, Jacob's reply on Wix-Users forum who gave very meaningful hints and I was then able to solve the problem. And problem was in Table:ImageFamilies, Column:MediaDiskId Value:2. This was suggested in MSDN tutorial and some other similar tutorials on net.
This value should be greater than the greatest number of DiskId in Media Table of your msi.
So, by
using Microsoft Orca, I simply opened my MSI's, Media Table and got the largest number from DiskID column, it was 5. And then using Orca, I edited my .pcp file and corrected value from 2 to 6 and that corrected the problem and I got my .msp file in hand.
image
Happy Patching... Smile

Wednesday, July 25, 2012

MSI: Admin install doesn’t extract all files…

While working with a Patch using Wix Patching, I did an Admin Install. But Pyro.exe complains that some files cannot be found. When I searched these in the output directory where Admin Installation deployed its files, those files were really missing. These were however present in msi and mentioned in Files table.
After some investigation, I got to know that the Feature with which these were attached, had a default Level=0 (Level 0 would disable the feature and so it will never install) and that’s the main cause that Admin Install was not installing these files.
So, by using Microsoft Orca, I simply changed the value in level Column from 0 to 3. (Or any other value greater than 0).
Orca_Feature_Level_Edit
And now Admin Install worked accordingly and Pyro.exe was also happy to give me my required patch.
There might be many reasons for keeping a Feature Level=0. During installation, there might be some Custom Action changing the Level or any condition accordingly. And that Custom Action or Condition might not be evaluated/scheduled during Admin Install.

Patching a build which has changed Component Ids (GUIDs)

Installer patches are used to patch an already installed product in order to update/add some more features or fixation of errors/bugs etc.
While creation a patch for a product about whom, the build procedure is not known to me, I first tried WIX provided Patch Creation Properties (.pcp file) method, which resulted in a big sized msp file (500+ MB). When I tried to apply the patch, it shows the setup dialogs for Updated build but failed with following message:
"Another version is already installed. You must first uninstall it in order to install this version."
I even changed the Product Code in the 2nd msi (in all tables), but  doesn’t solved any problem.
Then changing attribute value of WholeFilesOnly="no" from ‘yes’  under PatchCreation element reduced the size to 262 MB (I know its not a small size for a patch). But resulted in same error when tried to apply on installed product.
Alternatively, I tried msdn tutorial for using Patch Creation Properties (.pcp) file and that resulted in exactly same problem as that of Wix pcp case.
The I tried Wix Patching which actually supports making a patch by selectively adding Components to be patched on target machine. So I added few components, just to prototype it. And when Pyro.exe complaint about different GUIDs, that makes me to check for Component Ids (GUIDS) in both builds.
If you have installed Microsoft SDK 7.x then there would be a script file installed as C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\sysmgmt\msi\scripts\WiDiffDb.vbs. I used this file to get a difference report between the Updated Msi and Target msi and to my surprise, every Component Id (GUID) was changed in Updated build.
To confirmed my doubt, I then took differences between other versions and found that Component Ids were totally refreshed in every build.
Well, why we should not change the Component Ids without any specific reason,  can be measured from this article. And when to change Component GUIDs, read this.
Anyhow, I’m sure, that there could be some reason behind changing Component GUIDs in every build, but that causes problems in generating patches.
To cope with this situation, I played a small hack with the Upgraded msi.. Guess What.. here is the CSharp source code for that hack Smile.
C# - Update Component Ids
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using WindowsInstaller;
  7.  
  8. namespace msitest
  9. {
  10.     class Program
  11.     {
  12.         static void Main(string[] args)
  13.         {
  14.             string OrignalMSI = @"D:\ABD\OriginalBuild_225en1\MyProduct.msi";
  15.             string UpdatedMSI = @"D:\ABD\UpdatedBuild_351en1\MyProduct.msi";
  16.             
  17.             string strFileMsiNameOnly = Path.GetFileNameWithoutExtension(OrignalMSI);
  18.             string strDirectory = Path.GetDirectoryName(OrignalMSI);
  19.  
  20.             // Create an Installer instance
  21.             Type classType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
  22.             Installer inst = (Installer)Activator.CreateInstance(classType);
  23.  
  24.             Database OriginalMSIdb = inst.OpenDatabase(OrignalMSI, MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly);
  25.             Database UpdatedMSIdb = inst.OpenDatabase(UpdatedMSI, MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);
  26.             
  27.             
  28.             View OrgMsiView = OriginalMSIdb.OpenView("Select `Component`,`ComponentId` From Component");
  29.             View UpdMsiView = null;
  30.             
  31.             OrgMsiView.Execute(null);
  32.             
  33.             Dictionary<string,string> OrgMsiComponents=new Dictionary<string,string>();
  34.             Record OrgMsiRecord = OrgMsiView.Fetch();
  35.             
  36.             string updQuery="";
  37.  
  38.             while (OrgMsiRecord != null)
  39.             {
  40.                 Console.WriteLine(OrgMsiRecord.get_StringData(1) + " " + OrgMsiRecord.get_StringData(2));
  41.                 updQuery = "Update `Component` SET `Component`.`ComponentId`=" + "'" + OrgMsiRecord.get_StringData(2) + "'" + " WHERE `Component`.`Component`=" + "'" + OrgMsiRecord.get_StringData(1) + "'";
  42.                 UpdMsiView=UpdatedMSIdb.OpenView(updQuery);
  43.                 UpdMsiView.Execute(null);
  44.                 
  45.     
  46.                 //consolestring result = r.get_StringData(1);
  47.                 OrgMsiRecord = OrgMsiView.Fetch();
  48.             }
  49.  
  50.             UpdatedMSIdb.Commit();
  51.             // close the database
  52.             OrgMsiView.Close();
  53.             UpdMsiView.Close();
  54.         }
  55.     }
  56. }
Yes, reading Component Ids from Original MSI and replacing in Updated msi while comparing Component Names and making Component GUIDs same in both msi.
And now when I tried to create patch using Wix Patching … O Yes, it worked.. and I’ve working patch and when I tested, it worked as expected. Smile.Star
And then I tried to use Patch Creation Properties (*.pcp) methods again with this modified Updated msi, but in vain. Problem never changed Sad smile.
The only difference is that, this method needs a selection of Component manually, while in Patch Creation Properties (*.pcp) methods, it took whole builds differences and generates a patch upon these.
Although, Wix Patching is the only working solution I have in this situation, but Product owners are not happy with this Sad smile. Because now they have to select files manually.
Anyhow, I’m still looking for some other solutions. And you have some better solution/correction/Tutorial etc etc. you are most welcome to share it..