In Vista, a custom action, by default, does not run under the elevated privilege token that the user launches a setup under. I don't see the point in this, and apparently neither does everybody at Microsoft, since most of their custom actions they add to a project have a bit set in the Type field of their custom actions that elevate the privilege. Visual Studio does not provide a way for the rest of us to set this (or if they did, I couldn't find it in the docs or Googling for it).
I wrote this application. It basically takes two parameters, the name of an MSI file and the name of the file containing a custom action (not the name of the entry point) included in the MSI file. The application will identify any custom action associated with the file and mark it with elevated privileges. I run it as a Post Build event in my VS installer projects to make sure what I want to run actually runs.
If you see any problems with the code, please be kind enough to let me know and/or post it up here. This is my first MSI project and I'm sure I've screwed the pooch somewhere...
This is a ready-only archive of the InstallSite Forum. You cannot post any new content here. / Dies ist ein Archiv des InstallSite Forums. Hier können keine neuen Beiträge veröffentlicht werden.
Vista UAT Elevation
Started by
Carcass
, May 05 2007 20:33
1 reply to this topic
Posted 05 May 2007 - 20:33
CODE |
/* MSICustomActionElevator This application sets the bit on the Type field for a custom action to run under elevated privileges Parameters: [-w] MSIDatabaseFileName CustomActionFileName If you put in the -w, the app will wait for a key before closing Copyright 2007, Jason Terando You can use this for any commercial or non-commercial purposes. No warranty is implied - use at your own risk. */ #include "stdafx.h" #include <windows.h> #include <msi.h> #include <msiquery.h> #include <iostream> #include <conio.h> using namespace std; MSIHANDLE hInstall = NULL, hView = NULL, hRecord = NULL; bool Wait = false; LPCWSTR DatabaseFileName = L""; LPCWSTR CustomActionFileName = L""; // Clean up when we are done void Shutdown(int ExitCode) { if(hRecord != NULL) { MsiViewClose(hRecord); } if(hView != NULL) { MsiViewClose(hView); } if(hInstall != NULL) { MsiViewClose(hInstall); } if(Wait) { wprintf(L"Press any key to exit..."); while(_kbhit() == 0) { } } exit(ExitCode); } // Main routine int _tmain(int argc, _TCHAR* argv[]) { UINT result; WCHAR FileID[128] = {0}; if(argc < 2) { wprintf(L"Usage [-w] MSIDatabaseFileName CustomActionFileName\n -w = Wait for keypress at completion\n Press any key...\n"); while(_kbhit() == 0); exit(-1); } int i = 1; if(wcsicmp(argv[1], L"-w") == 0) { Wait = true; i = 2; } DatabaseFileName = argv[i++]; CustomActionFileName = argv[i]; wprintf(L"Opening \"%s\"\n", DatabaseFileName); result = MsiOpenDatabase(DatabaseFileName, MSIDBOPEN_DIRECT, & hInstall); if(result != ERROR_SUCCESS) { fwprintf(stderr, L"Unable to open database: 0x%08X\n", DatabaseFileName, result); Shutdown(-1); } // Find our custom action in the file table wprintf(L"Searching file table for \"%s\"\n", CustomActionFileName); result = MsiDatabaseOpenView(hInstall, L"SELECT `File`, `FileName` FROM `File`", & hView); if(result != ERROR_SUCCESS) { fwprintf(stderr, L"Unable to open file table: 0x08X\n", result); Shutdown(-2); } result = MsiViewExecute(hView, 0); if(result != ERROR_SUCCESS) { fwprintf(stderr, L"Unable to view file table: 0x08X", result); Shutdown(-3); } // Locate the file record matching our custom action while((result = MsiViewFetch(hView, & hRecord)) == ERROR_SUCCESS) { WCHAR FileName[_MAX_PATH]; DWORD dw = _MAX_PATH; MsiRecordGetString(hRecord, 2, FileName, & dw); if(dw > 0) { WCHAR * ptr = wcsstr(FileName, CustomActionFileName); if(ptr != NULL) { dw = _MAX_PATH; MsiRecordGetString(hRecord, 1, FileID, & dw); break; } } MsiViewClose(hRecord); } MsiViewClose(hView); // If we could not find the file, exit if(FileID[0] == 0) { fwprintf(stderr, L"Unable to locate custom action in file table\n", CustomActionFileName); Shutdown(-4); } // Get the custom action table entries for our file wprintf(L"Searching custom action table for matches\n"); WCHAR query[256]; swprintf_s(query, 256, L"SELECT Action, Type, Target FROM CustomAction WHERE Source='%s'", FileID); result = MsiDatabaseOpenView(hInstall, query, & hView); if(result != ERROR_SUCCESS) { fwprintf(stderr, L"Unable to open custom action table: 0x08X\n", result); Shutdown(-5); } result = MsiViewExecute(hView, 0); if(result != ERROR_SUCCESS) { fwprintf(stderr, L"Unable to view custom action table: 0x08X", result); Shutdown(-6); } bool needCommit = false; while((result = MsiViewFetch(hView, & hRecord)) == ERROR_SUCCESS) { WCHAR id[100]; int type; WCHAR target[1024]; DWORD dw = 100; MsiRecordGetString(hRecord, 1, id, & dw); type = MsiRecordGetInteger(hRecord, 2); dw = 1024; MsiRecordGetString(hRecord, 3, target, & dw); if((type & 0x800) == 0x800) { wprintf(L"%s is already privileged\n", target); } else { int newType = type | 0x800; wprintf(L"Updating type from %04X to %04X for %s\n", type, newType, target); needCommit = true; result = MsiRecordSetInteger(hRecord, 2, newType); MsiViewModify(hView, MSIMODIFY_UPDATE, hRecord); if(result != ERROR_SUCCESS) { fwprintf(stderr, L"Unable to update record: 0x08X", result); Shutdown(-7); } } MsiViewClose(hRecord); } // Commit changes if we made any if(needCommit) { wprintf(L"Committing changes\n"); result = MsiDatabaseCommit(hInstall); if(result != ERROR_SUCCESS) { fwprintf(stderr, L"Unable to commit database changes: 0x08X", result); Shutdown(-8); } } Shutdown(0); } |
Attached Files
Edited by Carcass, 07 May 2007 - 16:34.
Posted 16 May 2007 - 16:51
I didn't understand your implementation. It's right that VS 2005 configures the custom actions to run under in the impersonated custom action server in Windows Vista. The simplest method to run in the elevated custom action server is to change the type of the approbriate custom actions in the created package. To automate this, it is possible to use the PostBuildEvent. Copy the attached script into the project directory and insert the following statement in the PostBuildEvent property:
$(ProjectDir)\NoImpersonate.js "$(BuiltOuputPath)"
Hope this helps.
Andreas
$(ProjectDir)\NoImpersonate.js "$(BuiltOuputPath)"
Hope this helps.
Andreas
Attached Files
Edited by akerl, 16 May 2007 - 16:57.
Andreas Kerl
Inside Windows Installer 4.5
ISBN 3-86645-431-7