Surgically eliminating Windows Installer app repairs

My colleague, Jacques Bensimon sent over this fantastic write up on a common error scenario that probably has plagued us all at one time or another.  Thanks for sharing the knowledge JB!

Any of you who’ve dealt at all with application installations on a Windows image are familiar with the occasional repairs of MSI-installed applications triggered by launching an app, opening an associated document type, etc.  Most recently (the example I’ll use in what follows), I noticed that v12.x of the Citrix ICA client would trigger a repair any time I double-clicked a .ica file (this happened both on my laptop and on a XenApp 6 build I was working on).  As is always the case in such cases, figuring out why Windows Installer felt the need to perform a repair is easy — a 1004 event such as the one below can be found in the Applications event log:

clip_image002

As can be seen from the event log entry, this particular repair is triggered by the fact that the “resource” (in this case a Registry entry) HKLM\Software\Microsoft\Windows\CurrentVersion\Run\ConnectionCenter isn’t found.  Well, of course it isn’t found:  I manually deleted it right after installing the ICA client!  (Who needs Connection Center running in the background at all times, and in every user session in the case of a XenApp server?!).  In this particular case, the workaround is simple enough:  since Windows Installer checks for the existence of the Registry entry but doesn’t care about its actual value, re-creating an empty REG_SZ entry named “ConnectionCenter” at key HKLM\Software\Wow64\32\Node\Microsoft\Windows\CurrentVersion\Run resolves the issue with no undesired side-effect – notice the switch to the 32-bit Wow64\32\Node branch (where the original undesired value had been written):  on a 64-bit platform, the event log entry is to be interpreted in the context of the “bitness” of the app in question.  (By the way, if you care, the original value of the Registry entry was ““C:\\Program Files (x86)\Citrix\ICA Client\concentr.exe” /startup”).

But what about different Installer app repair issues that aren’t as easily worked around as this example?  What if the missing “resource” is an undesirable public desktop shortcut? or an unwanted .dot/.dotm macro file in MS Word’s common STARTUP folder?  What follows is a systematic description of how to convince Windows Installer to not check for a particular resource once it’s been established that the absence of that resource is responsible for triggering repairs.  I describe this approach as “surgical” to distinguish it from the “thermonuclear solution” you may also be familiar with:  using the (now officially deprecated) Microsoft utility MsiZap.exe (or its GUI front-end MsiCUU.exe, the MSI Cleanup Utility) to completely wipe away all Windows Installer data relating to the problematic application, which of course makes it impossible to uninstall or patch the app (unless it is first re-installed) and is, according to recent Microsoft noises, now considered unsafe for some reason (if this were Wikipedia, I’d have to give you a specific reference to that, but it isn’t, so I won’t).

In order to better explain the solution, a very quick overview of some Installer vocabulary is in order:  a given Windows Installer package (an MSI) defines the installation of one or more Products, what we typically call applications – the average MSI usually defines a single product, but more than one is allowed.  A product in an MSI consists of one or more Features:  our most familiar contact with MSI features is the case of an MSI installation wizard presenting a tree of application features and sub-features which can be individually selected or deselected (except for features that are not displayed and are therefore mandatory).  Even when no selectable features are presented during an attended setup, every product in an MSI consists of at least one feature.  Every feature in an MSI is made up of one or more Components – an MSI component is a fixed collection of folders, files, Registry keys and values, shortcuts, ODBC connections, etc. that are all installed together (no such thing as installing just part of a component).  A particular component can belong to more than one feature, so selecting any one of several features can force the installation of a particular component.  Finally, and this is the part that most interests us here, any component in an MSI can optionally be assigned (by whoever creates the installer package) a so-called “KeyPath”, typically a file, folder, Registry key or Registry value that the author considers either “fundamental” to that component or at least “representative” of that component.  When a component of an installed product is “activated” (i.e. executed) on a machine, Windows Installer  (always? often? sometimes?) verifies the existence of the component’s “KeyPath” (if one has been defined) as a quick check that the component is (still) present — it would presumably be impractical and time-consuming to verify the existence of every single item that  makes up the component — and initiates a repair if the “key path” is not found.  Using these terms, we now see that the generic form of the above 1004 event log entry is

Detection of product ‘{productGUID}’, featurefeatureName’, component ‘{componentGUID}’ failed.  The resource ‘KeyPath’ does not exist.

If the component in question hadn’t been assigned a KeyPath (which, as I stressed above, was completely optional), it could never trigger a repair.  Well, what if we simply make Windows Installer forget about the component’s keypath?  Turns out after a little digging (one more item off my bucket list) that the GUID of each component of all MSI-installed products is listed in the Registry as a subkey of HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components and that, as can be seen in the following screenshot, each component GUID key has a REG_SZ entry named after the GUID of the product to which the component belongs.  The value of that entry, if not blank, is the KeyPath for that component – make the value blank, and the KeyPath is gone, as are future repairs!

clip_image004

But wait, you don’t recognize the component’s GUID and the product’s GUID when comparing the Registry key to the event log entry?  The display format for GUIDs {involving curly braces} used in the event log entry is different from the laid out 32-digit hex strings used in the Registry.  The conversion is made obvious by the following little graphic (basically the first three digit groups are reversed and the last two are transcribed while flipping digit pairs):

clip_image006

One last thing:  if you need to install an MSI to multiple machines and would rather not wait until after installation to get rid of a troublesome component KeyPath, you can get rid of it at the source by creating a transform (.mst) using Microsoft Orca to remove the KeyPath associated with the component.  I won’t go into the details, but the following screenshot shows the Component table in the MSI with the row corresponding to our component highlighted (see the ComponentId column) – using the transform to blank out the KeyPath entry in that row (the yellow cell) will ensure that all future installations (using the transform) are free of that particular KeyPath.

This image has an empty alt attribute; its file name is proxy

Happy hunting!
Jacques

TAGS