Silent install with Win7 and UAC plugin
Asked Answered
J

0

6

I have an installer that can handle command-line parameters and /S silent installation. I recently upgraded the installer to better conform to standards for Vista / W7 UAC management by using the UAC plugin and switching the RequestExecutionLevel from admin to user.

The tests shown that the UAC plugin is working well for rights elevation in GUI mode and command line silent mode (though the "silent" installation is not actually completely "silent" due to the elevation dialog).

Now I am told by customers that while wrapping my setup into a third-party deployment tool, their tool is getting a 1223 (ERROR_CANCELLED) error code (that seems to be "elevation cancelled by user"). My setup does not return error codes directly via errorlevel, so I am guessing that this code is returned somewhere from the UAC plugin that seems to perform the elevation with a hack around the system "runas" dialog.

  1. am I right about the origin of the returned code? Though when I cancel the elevation dialog I get a errorlevel 5 (access denied) and not 1223

  2. to integrate the UAC plugin I am using a InitElevation macro that is call at the beginning of .onInit, is it OK?

  3. I am not sure to understand correctly the behavior of the UAC plugin in silent mode: the key seems to be in the _() function of the plugin dll, in the 0 case of the switch. If the NSIS dilaog is not visible (or not existent?) due to silent mode, could it make fail the "runas" invocation? In my test environment, while calling the silet setup from command line it is ok, but what if called from a deployment tool?

Macro to integrate the UAC plugin:

!macro InitElevation thing
    uac_tryagain:
    ${Debug} "Init UAC_RunElevated"
    !insertmacro UAC_RunElevated
    ;${debug} "$$0=$0 $$1=$1 $$2=$2 $$3=$3"
    ${Switch} $0
    ${Case} 0
        ${IfThen} $1 = 1 ${|} Quit ${|} ;we are the outer process, the inner process has done its work, we are done
        ${If} $3 <> 0 ;if we are admin
            System::Call "kernel32::GetCurrentProcessId()i.r0"
            ${If} ${UAC_IsInnerInstance}
                ; If we are in the elevated process, we need to get our grandparent PID for console
                ${GetProcessParent} $0 $ConsoleParentPID
                ;${Debug} "From elevated $0 process, parent process is $ConsoleParentPID"
                ${GetProcessParent} $ConsoleParentPID $ConsoleParentPID
                ;${Debug} "grand parent process is $ConsoleParentPID"
            ${Else}
                ;${Debug} "We are an already elevated process"
                StrCpy $ConsoleParentPID -1
            ${EndIf}
            ${Break}        ;we are admin (after elevation or not), let the show go on
        ${EndIf}
        ${If} $1 = 3 ;RunAs completed successfully, but with a non-admin user
            MessageBox mb_YesNo|mb_IconExclamation|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, try again" /SD IDNO IDYES uac_tryagain IDNO 0
        ${EndIf}
        ;fall-through and die
    ${Case} 1223
        MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "This ${thing} requires admin privileges, aborting!"
        Quit
    ${Case} 1062
        MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Logon service not running, aborting!"
        Quit
    ${Default}
        MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Unable to elevate , error $0"
        Quit
    ${EndSwitch}
    ${Debug} "End UAC_RunElevated init"
!macroend

Macro invocation (beginning of .onInit):

;abort if not started by administrator
!insertmacro InitElevation "installer"
${If} ${UAC_IsInnerInstance}
${AndIfNot} ${UAC_IsAdmin}
    SetErrorLevel 0x666666 ;special return value for outer instance so it knows we did not have admin rights
    Quit
${EndIf}
Journal answered 3/1, 2013 at 15:18 Comment(5)
I think I need the exact steps required to reproduce this, I have not touched the UAC plugin in ages and I usually advice people to stay away from it...Towill
@Anders: For now it is difficult to know precisely the environment as the problem occurs on a customer system, and with a deployment system that I do not have locally to test (Empirum). Could you elaborate on why you advise people not to use the UAC plugin and what should be a correct alternative?Journal
No alternative, if you are installing into ProgramFiles/HKLM then you are doing a all users/machine install and should not touch any users profile/HKCU. This also means that you should not have a run checkbox on the finish page since it will run as the wrong user... Basically, your install type should follow your RequestExecutionLevel value (highest allows for dual mode (SHCTX))Towill
@Anders: Well, my setupp allow a selection between "install for myself" / "install for everybody" and also display a final "run" checkbox : the UAC plugin is specifically useful for starting the application in the correct un-elevated profile after setup by administrator profile. It seems I am stuck on finding the plugin problem :)Journal
My take on this is that it is way too much work just for a run checkbox. I would recommend using "RequestExecutionLevel highest" and just hide the checkbox when installing for everybody or use nsis.sourceforge.net/ShellExecAsUser_plug-in, it is a bit of a hack and will in rare cases fail but it is much simpler to use...Towill

© 2022 - 2024 — McMap. All rights reserved.