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.
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
to integrate the UAC plugin I am using a
InitElevation
macro that is call at the beginning of.onInit
, is it OK?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 the0
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}