Monday, 26 February 2007

Installer error code 2869 - MSI and UAC on Vista

I ran into this problem today and couldn't find too much information on it. It happens when you try to run your installer that contains a custom action from the msi file only. When you run from the exe file everything works fine. This is to do with how the custom action interacts with (or fails to interact with) the windows user access control (UAC) in Vista. Your custom action requires elevated priveledges but it has not been given them.

First of all lets run the installer with a log:
msiexec.exe /i setup.msi /L*v log.txt
In the rather large log file we see:
MSI (s) (C8:6C) [16:20:10:162]: Invoking remote custom action. DLL: C:\Windows\Installer\MSIE4FD.tmp, Entrypoint: ManagedInstall
MSI (s) (C8!EC) [16:20:13:747]: Note: 1: 2262 2: Error 3: -2147287038
MSI (c) (44:CC) [16:20:13:757]: Note: 1: 2262 2: Error 3: -2147287038
DEBUG: Error 2869: The dialog ErrorDialog has the error style bit set, but is not an error dialog
MSI (c) (44:CC) [16:20:13:803]: Font created. Charset: Req=0, Ret=0, Font: Req=MS Shell Dlg, Ret=MS Shell Dlg

The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2869. The arguments are: ErrorDialog, ,
MSI (c) (44:CC) [16:25:00:976]: Note: 1: 2262 2: Error 3: -2147287038
The error is slightly misleading. It is to do with a lack of administrator priveldges for the custom action. To fix this we need to set the NoImpersonate bit on the custom action. Unfortunatly vs2005 does not let you do this easily. To resolve this take the following steps:
  • Add the following code to a new file called NoImpersonate.js:

// NoImpersonate.js
// Performs a post-build fixup of an msi to change all deferred custom actions to 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");

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

var sql
var view
var record

sql = "SELECT `Action`, `Type`, `Source`, `Target` FROM `CustomAction`";
view = database.OpenView(sql);
record = view.Fetch();
while (record)
if (record.IntegerData(2) & msidbCustomActionTypeInScript)
record.IntegerData(2) = record.IntegerData(2) | msidbCustomActionTypeNoImpersonate;
view.Modify(msiViewModifyReplace, record);
record = view.Fetch();


  • Add the file as an existing file to your setup project.
  • Find the PostBuildEvent in the properties for your setup project.
  • Set the PostBuildEvent to the following:
cscript.exe "$(ProjectDir)NoImpersonate.js" "$(BuiltOuputPath)"
  • Rebuild. You're done!

Edit number 2: I had thought that there was a typo with the build output path shortcut. I thought the typo is a missing t, however you may want to double check this when adding it to your post build events. Originally it was copied from msdn ( and if you use the macros button in the post-build event dialog in vs you still get $(BuiltOuputPath).


Martin said...

Thanks man, you just saved my night!


fufik said...

This solution saved me some troubles. My custom action attempts to attach a database to server but fails to do so. I assume it's also related to UAC, but have no idea how to check it or better how to make it work...

Any help?

Hunter555 said...

If you run the installer with logging it should give you an idea of what is going wrong:

msiexec.exe /i setup.msi /L*v log.txt

The log file will be rather large though so it might take you a while to find exactly what you are looking for.

One technique I use is to make sure your code runs in it's own project first (not in an installer) to make sure it is correct.

MegosAR said...

Thanks Hunter555,
I was researching the same problem for some time. That saved a lot. Not a word on Microsofts Web. Strange.

Nate said...

Awesome, this totally saved my butt. I had seen the noimpersonate bit elsewhere, but of course Visual Studio's setup projects have about 20% of the bare minimum you could want, so you can't access stuff like this.


Mathi said...

Hi Hunter,
I have the same problem with Vista.While Goggling ,I found your solution which is easier to me to understand.When implementing this,I got the following error :
'PostBuildEvent' failed with error code '1' 'Unspecified error'

Please help me out to solve this issue.


robertvw said...

I got it to work by adding some missing semicolons (;) at the end of some of the statements (I don't think that was it though) but mostly, there's a typo in the PostBuildEvent call, which should be:

cscript.exe "$(ProjectDir)NoImpersonate.js" "$(BuildOuputPath)"

Note that the original post has "Built" instead of "Build".


Hunter555 said...

Thanks robertvw, I edited the post to let people know to double check this. It's not very clear because both msdn and the visual studio macros button both point to $(BuiltOuputPath). (Note the missing t in output as well as built instead of build).

Bjorn said...


i tried this as well but when i build, it keeps saying
Runtime-fout Microsoft JScript: Het subscript valt buiten het bereik

in english i think it's somthing lik Runtime-fout Microsoft JScript: it's something about subscript and vs says it's on (24, 1)

anyone that knows the answer

Lakshmi said...

I have the same problem with Vista.
When i try to install my exe in Vista it throws an error code 2869. When i searched for solution i found urs to be easy. But when i implemented i got the error while building my setup.
'PostBuildEvent' failed with error code '1' 'Unspecified error'

Please help me out to solve this issue.


hunk said...

Didnt work for me at all

David said...

I get NoImpersonate.js(34, 1) Msi API Error: OpenDatabase,DatabasePath,OpenMode

Anyone else seen this?