In our build process there is currently the potential for non-code based files (such as image files) to be added to our web project, but not included in the MSI installer built by WiX.
To help prevent this, I want to perform the following in the AfterBuild target for our WiX project:
- Get a count of all files built (output from web deployment project)
- Get a count of all files built into MSI (from "File" table in MSI)
- Compare counts and fail build if they don't match
If I fire up Orca I can easily see the File table and count, but I don't know how to automate this from MSBuild. Is there some API or other mechanism to get this information out of an MSI?
I don't mind writing a custom MSBuild task to extract the MSI File table count.
Create a new visual studio project, add a reference to
c:\windows\system32\msi.dll
and use the following code to read the number of files in a msi file:This code uses the
WindowsInstaller.Installer
COM object, which is the entry-point for the windows installer automation API. Take a look at the complete reference documentation.edit: apparently wix comes with managed assemblies (in
C:\program files\Windows Installer XML v3\sdk
) which wrap msi.dll. I guess this is what Rob is referring to by "DTF" in his answer. Using the types in the Microsoft.Deployment.WindowsInstaller assembly and namespace would simplify the code sample to this:WinRAR identifies the MSI as a self-extracting CAB archive (after giving it a .rar extension). I suppose you could copy the file somewhere, rename it, unpack it with WinRAR, then count the files. The files will not have their original names, though.
This seems a bit outdated and I don't know if it could be of any help.
MSI files are little baby databases with a custom SQL engine. You just need to run the query:
and count the number of rows that come back. Easiest way to integrate into an MSBuild Task would probably be to use WiX's DTF which provides managed wrappers for all of the MSI APIs.
The solution will be really simple once you get all the tools in place.
Since there are multiple ways you could implement this, i'm answering my own question with the results I'm now using thanks to the answers from wcoenen and Rob.
This is the custom MSBuild task:
Couple of things to note:
Here are the corresponding unit tests, assumption is you have Test.msi in your test project which is copied to the output directory.