Problem
When creating an installer with custom actions you might run into some security issues when executing it on a Windows Vista/7/2008 or later OS.
This is because custom actions will be executed in the context of the user running the Windows Installer Service being the SYSTEM user.
This behavior is enforced from Windows Vista on and can give you authorization problems for certain tasks you want to perform in your custom actions.
This is because custom actions will be executed in the context of the user running the Windows Installer Service being the SYSTEM user.
This behavior is enforced from Windows Vista on and can give you authorization problems for certain tasks you want to perform in your custom actions.
Solution
To overrule this default behavior and run the custom actions as the impersonated user that is executing the MSI we will have to flip the msidbCustomActionTypeNoImpersonate bit that is on by default.
In a Visual Studio Setup project it is however not possible to set this flag through the Properties Window.
To solve this we must create a post-build script that will flip this bit:
In a Visual Studio Setup project it is however not possible to set this flag through the Properties Window.
To solve this we must create a post-build script that will flip this bit:
// CustomAction_Impersonate.js <msi-file>
// Performs a post-build fixup of an msi to change all deferred custom actions to Impersonate
// 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();
//Loop through all the Custom Actions
while (record)
{
if (record.IntegerData(2) & msidbCustomActionTypeInScript)
{
//We must flip the msidbCustomActionTypeNoImpersonate bit only for deferred custom actions
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);
}
This script file (CustomAction_Impersonate.js) must be placed in the same folder as your setup project (Setup.vdproj) and add the following PostBuildEvent in your setup project:
cscript.exe "$(ProjectDir)CustomAction_Impersonate.js" "$(BuiltOuputPath)"
cscript.exe "$(ProjectDir)CustomAction_Impersonate.js" "$(BuiltOuputPath)"
Build and run your setup project and you will notice that all the custom actions will now run as the impersonated user that executes the MSI.
Author: Christophe