Script to set NoImpersonate bit for custom actions in Visual Studio 2005 setup projects

I previously posted a set of steps that can be used to toggle the NoImpersonate bit for custom actions in MSI-based setups created with Visual Studio 2005 setup projects.  This type of script is necessary because custom actions created in the VS setup project designers do not have this attribute, and there is no way to set this attribute via the UI.

Unfortunately, my file server has been unreliable lately, which has made it difficult to download the Jscript file used in this in these instructions.  As a result, I decided to post the source code for that script here so you can copy and paste it into a file for use in your build process.

Here are the instructions that can be used to modify an MSI built in VS 2005 to set the NoImpersonate attribute for all deferred custom actions:

  1. Copy and paste the code listed below and save it to the directory that contains the Visual Studio project you are working on with the name CustomAction_NoImpersonate.js (or download the sample script and extract the contents to the project directory)
  2. Open the project in Visual Studio 2005
  3. Press F4 to display the Properties window
  4. Click on the name of your setup/deployment project in the Solution Explorer
  5. Click on the PostBuildEvent item in the Properties window to cause a button labeled "..." to appear
  6. Click on the "..." button to display the Post-build Event Command Line dialog
  7. Add the following command line in the Post-build event command line text box:
    cscript.exe "$(ProjectDir)CustomAction_NoImpersonate.js" "$(BuiltOuputPath)"
  8. Build your project in Visual Studio 2005 - now all deferred custom actions will have the NoImpersonate bit set for them

Here is the source code for CustomAction_NoImpersonate.js.  You can cut and paste all of the text below into a file and save it to your computer to use with your setup projects:

// Usage: CustomAction_NoImpersonate.js <msi-file>
// Performs a post-build fixup of an MSI to change all
// deferred custom actions to include NoImpersonate

// Constant values from Windows Installer
var msiOpenDatabaseModeTransact = 1;

var msiViewModifyInsert = 1
var msiViewModifyUpdate = 2
var msiViewModifyAssign = 3
var msiViewModifyReplace = 4
var msiViewModifyDelete = 6

var msidbCustomActionTypeInScript = 0x00000400;
var msidbCustomActionTypeNoImpersonate = 0x00000800

if (WScript.Arguments.Length != 1)
{
  WScript.StdErr.WriteLine(WScript.ScriptName + " file");
  WScript.Quit(1);
}

var filespec = WScript.Arguments(0);
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

var sql
var view
var record

try
{
  sql = "SELECT `Action`, `Type`, `Source`, `Target` FROM `CustomAction`"
  view = database.OpenView(sql);
  view.Execute();
  record = view.Fetch();
  while (record)
  {

    if (record.IntegerData(2) & msidbCustomActionTypeInScript)
    {
      record.IntegerData(2) = record.IntegerData(2) | msidbCustomActionTypeNoImpersonate;
      view.Modify(msiViewModifyReplace, record);
    }
    record = view.Fetch();
  }

  view.Close();
  database.Commit();
}
catch(e)
{
  WScript.StdErr.WriteLine(e);
  WScript.Quit(1);
}