RemoveFile Table

The RemoveFile table is pretty handy to know and use. It will remove any folders/files that you indicate during installation, uninstall (or either), one the RemoveFiles action is run (default action, usually before installfiles). It can use the * wildcard which is nice as well. Each entry also is attached to a component so you can perform conditions if needed.

The one downside is that the directories you want to remove files from HAS to be in the directory table. So it is possible to have to create many directory entries if they don't already exist in the msi. Worse if profile directories are not already defined aka Local Application Data dirs.

I have used this table to remove existing config files, that are not removed/updated in the upgrade process (to ensure my custom one is installed instead of skipped). Remove/clean up files created by the app exe, that msi uninstall will normally not remove. I have even used this table to remove all files from a previous version of the app (poor man's uninstall) because I could not silently run the existing native uninstall.

Official MS Documenation

Columns

FileKey
Primary key used to identify this particular table entry.

Component_
External key the first column of the Component table. This field references the component that controls the file to be removed.

FileName
This column contains the localizable name of the file to be removed. If this column is null, then the specified folder will be removed if it is empty. All of the files that match the wildcard will be removed from the specified directory.

DirProperty
Name of a property whose value is assumed to resolve to the full path to the folder of the file to be removed. The property can be the name of a directory in the Directory table, a property set by the AppSearch table, or any other property that represents a full path.

InstallMode
Must be one of the following values.

Constant Hexadecimal Decimal Description
msidbRemoveFileInstallModeOnInstall 0x001 1 Remove only when the associated component is being installed (msiInstallStateLocal or msiInstallStateSource).
msidbRemoveFileInstallModeOnRemove 0x002 2 Remove only when the associated component is being removed (msiInstallStateAbsent).
msidbRemoveFileInstallModeOnBoth 0x003 3 Remove in either of the above cases.

EXAMPLE

FileKey Component_ FileName DirProperty InstallMode
JTRAX_LEG_FILES HC_HKCU * JTRAX_LEG_DIR 3
JTRAX_LEG_FOLDER HC_HKCU JTRAX_LEG_DIR 3

In the example above, I wanted to remove an install directory and all files inside of it from a legacy install of an older version, poor man's uninstall routine as it were.

FileKey: As per the docs, this is just a unique name for the table, I almost always use all caps, InstallShield seems to populate drop downs etc in other areas if all caps. In this case I created one entry to remove the files and the other to remove the actual directory.

Component_: This is the component associated to the records in the table. This app didn't have conditions, but if it did the RemoveFile entry would only be completed if this component was used. In this case I created a HKCU component for self-heal, to ensure the files/dir are removed if still present during self-heal.

FileName: For the Files entry I used the wildcard of *, to remove all files in the directory. I have used *.lnk for shortcuts in the past etc. The Folder entry which is blank will remove the folder. MSI is smart enough to delete the files, then the folder, it will not remove a folder if files/folders are present in the dir. One of the downsides, RemoveFile is not recursive so you have to have an entry for files in each dir, and the dir itself. So if you have a deep folder structure the records can add up.

DirProperty: This is the unique key for the Directory Table entry, specifying which folder to remove files from (or remove dir). In this case I created the folder structure of c:\JTrax in the directory table, the "Jtrax" dir had a unique name of JTRAX_LEG_DIR. Since I only wanted to remove files from this dir, then remove the dir itself; only that directory table record was used.

InstallMode: This pretty much tells the record to remove files/folders during install (1), uninstall (2) or both (3). In this case since I was removing a legacy install, I chose both (aka 3)