Search code examples
c#visual-studio-2017windows-installercustom-action

Installer Projects - Launching a custom action with elevated privileges


I have a Visual Studio 2017 c# application with an installer projects installer attached to it. We use a "custom action" to launch an executable which runs as the MSI is finishing, and the custom action is under "commit" in the custom actions tab.

When the application runs, its windows user principal is NT AUTHORITY\SYSTEM.

When I run the application myself, its user is me, MYDOMAIN\MYUSER

So I am trying to get it to elevate those permissions, and so far from googling mainly on old stackoverflow questions I found three possible resolutions but none of them worked for me, in all cases the exe was still running under NT AUTHORITY\SYSTEM

  1. Add an app manifest that contains
<requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
  1. Edit the vdproj file in notepad to make RequiresElevation "true"
    "MsiBootstrapper"
    {
        "LangId" = "3:1033"
        "RequiresElevation" = "11:TRUE"
    }
  1. Tried adding AdminUser as a launchcondition, as per:How do I avoid UAC when my EXE file name contains the word "update"?

The above have been tried all together and separately but its always still the SYSTEM user.

Any ideas on how I can get the custom action to run as the logged-in user's privileges and not as SYSTEM ? thanks


Solution

  • The EASY answer turned out to be the accepted answer in this thread:

    Windows installer using the NT AUTHORITY\SYSTEM instead of login user

    [quote]

    The short answer is that you can't do this in a Visual Studio setup that is an InstallAllUsers setup because the all VS installer generated custom actions run as the system account. Therefore you'd need to change the custom action settings in the MSI file with an editing tool such as Orca. You'd find the custom action in the CustomAction table in the MSI file, look at the Type values (it's probably a type 3074) and then turn off the msidbCustomActionTypeNoImpersonate bit so that it runs impersonated as the installing user.

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa368069(v=vs.85).aspx

    Note that running impersonated as the installing user has its own set of issues because it is NOT the same as running as the interactive user. The user profile is not loaded, so objects associated with the user (such as HKCU, user profile folders) are very unreliable.

    Many people populate the databases with a separate programs the first time the application is launched so that it runs properly as the interactive user and can be developed and debugged as a standalone program. If the populate fails during the install you either give up the install and roll back, or you continue the install and end up with an empty database, for which you might need a program to populate it anyway. [/quote]

    The NOT SO EASY ANSWER but excellent solution was as follows:

    Edit the MSI file to remove the type msidbCustomActionTypeNoImpersonate from the custom action record.

    I did this programmatically in a VB.NET program as follows:

        Dim o As WindowsInstaller.Installer = CType(CreateObject("WindowsInstaller.Installer"), WindowsInstaller.Installer)
    
        Dim db As WindowsInstaller.Database
        db = o.OpenDatabase(fil.FullName, WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabaseModeDirect)
    
        Dim record As WindowsInstaller.Record = Nothing
        view = db.OpenView("select File.File, FileName From File")
        view.Execute(record)
        record = view.Fetch
        Dim bFound As Boolean = False
        While record IsNot Nothing
            Dim sFileName As String = record.StringData(2)
            If sFileName.EndsWith("MYCUSTOMACTIONEXE.exe", StringComparison.CurrentCultureIgnoreCase) = True Then
                bFound = True
                Exit While
            End If
            record = view.Fetch
        End While
    
        If bFound = True Then
            Dim sGUID As String = record.StringData(1)
    
            '   At time of writing this was changing a 3602 into a 1554, so removing msidbCustomActionTypeNoImpersonate 
            '   The record key was _65BF5279_D2EA_42C1_AC66_90A684817EE5 which is the custom action for MYCUSTOMACTIONEXE.exe
    
    
            view = db.OpenView("select Action, Type From CustomAction Where Source = '" & sGUID & "'")
            view.Execute(record)
            record = view.Fetch
            If record IsNot Nothing Then
                Dim sActionGUID As String = record.StringData(1)
                Dim sType As String = record.StringData(2)
                If sActionGUID IsNot Nothing AndAlso sActionGUID <> "" Then
                    '   Take off Hex 800 which means noimpersonation
                    Dim lType As Integer = CInt(sType)
                    If lType And 2048 = 2048 Then
                        Dim sNewType As String = CStr(lType - 2048)
                        Dim v As WindowsInstaller.View = db.OpenView(
                            "update CustomAction set Type=" & sNewType & " Where CustomAction.Action = '" & sActionGUID & "'")
                        v.Execute()
                    End If
                End If
    
            End If
        End If