External handler for msiexec MsiSetExternalUI

Good morning,

I am looking to achieve an external handler for msiexec, but not stopping msiexec from acting any different. I would like to be able to intercept all messages utilising the MsiSetExternalUI but still having the same responses and dialogs to the end user.

My main aim is intercept where the cached source for msi are installed from and move them to another location.

I have tried utilising logging utilise the logging registry key, but source location of packages can get deleted and the source of the package will not exist by the time i have intercepted the log file and got the location of the msi.

For example embedded msi in a setup exe especially old C++ redistributable extract themselves with the redist to a random directory on the root of the homedrive and install, then on completion delete the directory. The behaviour of msiexec isn't consistent as majority of packages are cached in the windows installer dir c:\windows\installer and the original packages cached in the c:\programdata\cached packages.

Why are some packages cached and others arent?

Hence the reason why i would like to utilise the External UI, but ensure that the behaviour is kept the same.

I am currently testing a project with

MsiInterop.MsiSetExternalUI(new MsiInstallUIHandler(_OnExternalUI), MsiInstallLogMode.ExternalUI, IntPtr.Zero);

Any ideas or examples would be really helpful.


"Intent"

We have some problems in deployment that people tell us what they are doing, but not what they are intending. Sometimes this causes us to write elaborate answers that doesn't answer the question. I hope this is not the case here.

Attempted Answer

You want to find the exact path to the MSI that is cached during installation under %SystemRoot%\Installer during installation of your MSI?

I have never tried it, but saschabeaumont posted a VBScript ages ago that appear to try to do what you want (albeit not during the install itself): WiX Custom Action - MSI copy itself. I have never tried this script and don't really want to recommend it.

With regards to the C++ redist stuff: I am not sure exactly what they are doing, but Microsoft tends to rewrite their own rules all the time and they do stuff - at times - that make no sense when analyzed. I wouldn't try to spend too much time trying to understand it - unless you absolutely have to. Just my 2 cents.


Can we ask the obvious: why do you need this copy? Perhaps there is a better way to achieve what you want? Below is a little overview of different folders used to cache MSI files and some links with info on MsiSetExternalUI.


MsiSetExternalUI

I don't see how you need to access the log like you are trying to with MsiSetExternalUI to achive your MSI file caching, but here are some links for its use:

  • Logging and filtering with MsiSetExternalUI (serverfault.com).
  • Wrapping the Windows Installer 2.0 API.
  • Handling Progress Messages Using MsiSetExternalUI.

More on MSI Caching

There are several forms of MSI caching - some built into Windows Installer, and others implemented by third party tools and certain Microsoft tools have their own way of deploying things (such as Visual Studio).

Here are some hints on how MSI files can be cached on your system. This will by no means be complete, but it is what I can write off the top of my head:

1. Windows Installer (msiexec.exe) caching

There is a built-in Windows Installer feature to cache a copy of the original MSI installation database during installation. This cached copy used to be stripped of internal CAB files (making them much smaller than the original file), but this changed around Windows 7 and the MSI copies are now cached full-size (follow link for details).

The folder where the MSIs are cached is: %SystemRoot%\Installer (normally C:\Windows\Installer). Each MSI is assigned a random hex name. All MSI files will make it into this cache folder - unless something went wrong during installation or product registration. An MSI file missing from this folder is a serious problem - the product is then generally un-uninstallable, and un-upgradeable. We are starting to see problems with certain security software quarantining MSI files from this folder - it can be a nightmare to deal with - but that is besides the point for this answer.

Beyond this built-in mechanism, third party vendors may cache the original installation MSI in other locations as well as this built-in cache folder. This is to support repair, patch and modify operations without any requests for "source media". Great for home and small office users, but it may not be appreciated by corporate users who have all installation sources available on network shares accessible from all workstations (they don't like such local copies). To accomplish this they generally use MSI's built-in administrative installation feature - essentially a standardized way to create a network location share to trigger the installation from with extracted files (there is a another description of administrative installations here - perhaps more practically oriented than the first one).

UPDATE: In all honesty, I think optional caching of source files should have been built into Windows Installer from the start and be the default command line option (for home and small office users), and then a simple flag could prevent such caching easily for all corporate users (for example NOSOURCECACHING = 1). Also: now that MSI files are cached full-size in %SystemRoot%\Installer - it still seems you can't auto-magically get source files from there? (not tested recently). What is up with that? The files are there - unless the install happened from an administrative image (in which case the source is probably safely located on a network share and accessible when needed so local PC clutter can be avoided). Oh well, in the future we will no doubt pull files directly from online repositories on-demand, so one problem solved and a bunch of new ones in the pipeline? Malware, spoofing and injection? Remote files deleted without warning (to get rid of vulnerable releases that should no longer be used - leaving users stranded)? Certificate and signature problems? Firewalls & proxy issues? Auto-magic updates with unfortunate bugs hitting everyone immediately? Just ranting :-). I am sure it will largely be an improvement. Anyway, onwards to current third party caching approaches (not MSI standard) in the sections below.

2. WiX caching

The WiX bundle feature (Burn) can cached MSI files on the system. I am not 100% sure how they do this to be honest, I hope Arnson or Mensching can correct me here if I am wrong. However, I believe they use: %ProgramData%\Package Cache (normally C:\ProgramData\Package Cache) for their caching. There are a lot of different Microsoft components in here on my system, and I am not sure if they are all packaged with WiX.

3. Installshield caching

Installshield can cache original MSI files in %SystemRoot%\Downloaded Installations for certain types of build configurations. In other words: not all Installshield setups will cache themselves this way - it is an Installshield project build setting that can be switched on or off as desired by the setup developer.

UPDATE: It seems newer versions of Installshield may now cache setups by default at %LocalAppData%\Downloaded Installations (normally C:\Users\YOURUSERNAME\AppData\Local\Downloaded Installations) instead of %SystemRoot%\Downloaded Installations. I am not sure which version switched to this location. Maybe Michael Urman of Installshield can help us?

4. Advanced Installer caching

Added by Bogdan Mitrache of Advanced Installer (many thanks - now it is accurate): The easiest way to get/copy of an MSI from an Advanced Installer built EXE is to use the /extract command line option.

At install time, for EXE builds (MSI bundled inside EXE) Advanced Installer extracts the contents by default in this location:

[AppDataFolder][|Manufacturer]\[|ProductName] [|ProductVersion]\install.

As you can see, it is vendor dependent, so the path is different for each package.

Also, this path is customizable from within the setup project, so users can change it (most of the time they don't).

There is also the option to delete the extracted resources when the installation is complete, again this is user configurable and on by default.

If you're building a standard MSI with Advanced Installer then the caching is done by Windows Installer, as explained above.

5. Visual Studio caching

Visual Studio appears to cache packages under: %AllUsersProfile%\Microsoft\VisualStudio\Packages (normally C:\ProgramData\Microsoft\VisualStudio\Packages). I don't really have a clue how they do things apart from this folder being used. There are also packages here: %ProgramData%\Microsoft\VisualStudio\Packages.

UPDATE: the folder %ProgramData%\Microsoft\VisualStudio\Packages appears to be the same location as above (%AllUsersProfile%\Microsoft\VisualStudio\Packages) only with a symbolic link (the folders point to the same files and folders on disk). It is also possible to disable this caching as described by Heath Stewart here: Moving or disabling the package cache for Visual Studio 2017.

And this is non-MSI and not well-known to me: %ProgramFiles(x86)%\Microsoft SDKs\NuGetPackagesFallback

6. Other Cache Folders?

Apple: I don't know much about it, but it seems Apple may use this folder to cache some of their MSI installers: %LocalAppData% \Apple\Apple Software Update\ (normally C:\Users\Acer\AppData\Local\Apple\Apple Software Update).

Sun: it seems Sun uses this base folder to cache Java installation MSI files: %UserProfile%\AppData\LocalLow\Oracle\Java (normally C:\Users\Acer\AppData\LocalLow\Oracle\Java).

There are no doubt many other cache folders in use.