Home > Installshield, Software Deployment > Major Upgrade using Product Code

Major Upgrade using Product Code

Caution: This is NOT best practice!  But when your back is against a wall, you need a way out.  This was my way out/solution.

We recently got ourselves stuck up a creek without a paddle, so I had to fabricate a paddle and here’s how I did it. This code will comb the registry for the existence of a list of supplied product codes and attempt to uninstall the first one found in the UI Sequence using msiexec /x.

The back story of why we needed this isn’t really important, but I’ll share the synopsis.  We have 2 types of installers and the second type is more or less a trial that has ~25 flavors.  The two types of installers can co-exists on the same machine (unique upgrade codes).   Well for one reason or another it was decided that this should no longer be the case and for manageability we would combine the two sets of flavors into one upgrade code so only one product can be installed on a machine at a time.  This was done and we performed a release.  Months later the Marketing dept caught wind of this and wanted the old behavior back to allow for both the flavors to co-exist on the machine at a time. (2 different Upgrade Codes)  THIS WAS A PROBLEM.  Now that the 2 flavors of our software share the same upgrade code, they are identical as far as MSI is concerned and there is no way to delineate between the two in order to perform major upgrades.  — So this is when I came up with the following solution we’ve had in place for awhile. (Sorry, .. long ‘synopsis’)

MSI can only perform major upgrades using Upgrade Codes.  There’s no built in mechanism for using a Product Code to uninstall a product.  Here’s how I’m targeting specific Product Codes of our past release (25 individual products) and manually uninstalling the first one found using msiexec.exe /x during the UI Sequence.  (Can’t be done during the Execute sequence because msi-chaining is not permitted).  The following is Installscript.


//===========================================================================
//
//  Function:    UninstallIfProductCode()
//
//    Description: Removes specific product codes.  Removes one and then returns.
//    Note:      (There would only ever be one on the system.)
//===========================================================================

export prototype VOID UninstallIfProductCode(HWND);
function VOID UninstallIfProductCode(hMSI)

STRING  szProductNumber,szCompressedGuid,szKey;
LIST productCodes;
NUMBER nvItem,nResult;

begin
    productCodes = ListCreate(STRINGLIST);
    ListAddString(productCodes, "{EAFD321F-7441-49F7-845F-162AFE9A9E89}", AFTER);
    ListAddString(productCodes, "{15219BB7-218A-4CA9-B904-E9730A5AE831}", AFTER);
    ListAddString(productCodes, "{831E34B1-844F-485D-95F6-0B4324D30F3F}", AFTER);
    ListAddString(productCodes, "{2ECC9820-1A29-4860-8A0B-BD1CE320B4B2}", AFTER);
    ListAddString(productCodes, "{A8CA60A2-5C80-4862-B539-72A0FE164631}", AFTER);
    ListAddString(productCodes, "{BF0ADDB3-FBF4-45F3-8862-739B43D10F09}", AFTER);
    ListAddString(productCodes, "{240047B1-1ED9-42DB-AC97-547D9C7B639C}", AFTER);
    ListAddString(productCodes, "{02161687-5FB6-4123-9786-C6D41DA34B8E}", AFTER);
    ListAddString(productCodes, "{33CAB057-95D1-40EC-A0C3-C116E4E3A58D}", AFTER);
    ListAddString(productCodes, "{E3028A13-E396-47AA-ACB6-DE4F51954F0C}", AFTER);
    ListAddString(productCodes, "{DCD725C7-BB93-49FF-AFA3-BD2FA96EC048}", AFTER);
    ListAddString(productCodes, "{57CB7704-9BAA-407C-B3A8-EA8184CABF66}", AFTER);
    ListAddString(productCodes, "{F67AA111-D082-4187-932B-9186DA4E2F6B}", AFTER);
    ListAddString(productCodes, "{AEC516A4-6929-43B0-A4FD-3E7F9BFBBCBA}", AFTER);
    ListAddString(productCodes, "{BB9B1A98-7A23-400D-B8BD-CBD7C3D2B839}", AFTER);
    ListAddString(productCodes, "{E1BB77D9-C487-4AB1-BA9C-7CD752A63E5E}", AFTER);
    ListAddString(productCodes, "{08C40B1B-B1D2-4DD2-87E1-677AAE040CBF}", AFTER);
    ListAddString(productCodes, "{FB485301-53C7-4011-9256-3E7F9C92AC5F}", AFTER);
    ListAddString(productCodes, "{9CAAE3D3-17D8-44CD-8659-62E29E64C64B}", AFTER);
    ListAddString(productCodes, "{9CE9C04A-ADD6-45C6-90E3-4E56EDB2CB3C}", AFTER);
    ListAddString(productCodes, "{724FCA6E-07C0-4D18-95A2-04CE0450A912}", AFTER);
    ListAddString(productCodes, "{35DC018B-4DCF-42B9-B898-718EDEACAFD8}", AFTER);
    ListAddString(productCodes, "{AA8B768D-5483-4D6C-8E73-12983D727C59}", AFTER);
    ListAddString(productCodes, "{59C22288-4019-4179-B303-D7274F23457A}", AFTER);

    nResult = ListGetFirstString(productCodes, szProductNumber);

    while (nResult != END_OF_LIST)

        szCompressedGuid = CompressedGUID(szProductNumber);

        RegDBSetDefaultRoot(HKEY_CLASSES_ROOT);
        REGDB_OPTIONS = REGDB_OPTIONS | REGDB_OPTION_WOW64_64KEY;  //let's be 64bit aware

        if(RegDBKeyExist(szKey) > 0) then
            LaunchAppAndWait("msiexec","/x " + szProductNumber + " /qb /passive", WAIT);
            goto productFound:
        endif;

        nResult = ListGetNextString (productCodes, szProductNumber);
     endwhile;

    productFound:
    ListDestroy(productCodes);
end;

Note: The code for the CompressedGuid() function can be found in one of my earlier blog posts: Installscript to Transform GUID into ‘Compressed GUID’.

Like I mentioned, we’ve had this in place for a couple releases without any reported problems.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

%d bloggers like this: