I think there should be an option for programs that need to be executed as a normal/standard user but require the launcher to have administrative rights. If you don't know what I'm talking about you can read up on this topic here.
So within the AppNameLauncher.ini
file there could be a new key such as [Activate]ExecAsUser=true
and we could add/change the code in the PortableApps.comLauncher.nsi
file to something like this (I pulled directly from the code in my variant of PAL and edited/removed minor/unrelated code but the concept is just the same in essence):
;= I use !searchparse because we need to set this definition
;= but need it to be set outside of a function/section.
!searchparse /ignorecase /noerrors /file `${PACKAGE}\App\AppInfo\Launcher\${AppID}.ini` `ExecAsUser=` ExecAsUser
;= Sets/Unsets the define
!if ! ${ExecAsUser} == "" ;= If it is not empty
!if ${ExecAsUser} == true ;= If it is true
!define /REDEF ExecAsUser ;= already set to true but we redefine ExecAsUser to nullify it
!else if ${ExecAsUser} == false ;= If it is false
!undef ExecAsUser ;= than we undefine it
!else ;= If anything other than true or false
;= the following !error instruction will stop the compiler
;= and will show the message that follows
!error "The key 'ExecAsUser' has an invalid value."
!error "Please review the Launcher.ini file and be sure it has a true/false value set."
!endif
!else ;= otherwise it must be empty
!error "ExecAsUser is empty but needs a true/false value! Please check the Launcher.ini file.
!error "If this feature isn't needed, than delete the key."
!endif
;= Code to include the StdUtils plugin using the concept I shared on GitHub
;= https://github.com/PortableApps/Launcher/issues/4#issuecomment-330439105
;= See footnote 3
!ifdef ExecAsUser
!include StdUtils.nsh
!ifndef PLUGINSDIR
!define PLUGINSDIR
!AddPluginDir Plugins
!endif
!endif
;= This could also be another feature to add this plugin which gives a developer
;= the ability to use this plugin within the custom.nsh file without using ExecAsUser
!ifdef StdUtils
!ifndef ExecAsUser
!include StdUtils.nsh
!ifndef PLUGINSDIR
!define PLUGINSDIR
!AddPluginDir Plugins
!endif
!endif
!endif
;= The main codebase for the ExecAsUser proposal
Function Execute ;{{{1
${EmptyWorkingSet}
ClearErrors
${ReadLauncherConfig} $0 Launch HideCommandLineWindow
${If} $0 == true
StrCpy $ExecString "$ExecString $Parameters"
ExecDos::exec /TOSTACK $ExecString
Pop $0
${Else}
${IfNot} ${Errors}
${AndIf} $0 != false
${InvalidValueError} [Launch]:HideCommandLineWindow $0
${EndIf}
${If} $WaitForProgram != false
!ifdef ExecAsUser ;= This should have been set earlier in the script using !searchparse
${ConfigReads} `${CONFIG}` ExecAsAdmin= $0 ;= See footnote 1 below for why this is here.
${If} $0 == true
StrCpy $ExecString "$ExecString $Parameters"
ExecWait $ExecString
${Else}
${StdUtils.ExecShellAsUser} $0 "$ExecString" "" "$Parameters" ;= Pick-a-boo!
${EmptyWorkingSet}
Sleep 1000
${GetFileName} $ProgramExecutable $1
${EmptyWorkingSet}
${Do}
${ProcessWaitClose} $1 -1 $R9
${IfThen} $R9 > 0 ${|} ${Continue} ${|}
${LoopWhile} $R9 > 0
${EndIf}
!else
ExecWait $ExecString
!endif
${Else}
!ifdef ExecAsUser
${StdUtils.ExecShellAsUser} $0 "$ExecString" "" "$Parameters" ;= I see you! =)
!else
Exec $ExecString
!endif
${EndIf}
${EndIf}
${If} $WaitForProgram != false
ClearErrors
${ReadLauncherConfig} $0 Launch WaitForOtherInstances
${If} $0 == true
${OrIf} ${Errors}
${GetFileName} $ProgramExecutable $1
${EmptyWorkingSet}
${Do}
!ifdef Sleep ;= This is another idea I have.. See footnote 2 below for why this is here.
Sleep ${Sleep} ;= ${Sleep} is set earlier in the script and is a number in milliseconds
!endif
${ProcessWaitClose} $1 -1 $R9
${IfThen} $R9 > 0 ${|} ${Continue} ${|}
StrCpy $0 1
${Do}
!ifdef Sleep
Sleep ${Sleep}
!endif
ClearErrors
${ConfigReadS} `${LAUNCHER}` WaitForEXE$0= $2
${IfThen} ${Errors} ${|} ${ExitDo} ${|}
ExpandEnvStrings $2 $2
${ProcessWaitClose} $2 -1 $R9
${IfThen} $R9 > 0 ${|} ${ExitDo} ${|}
IntOp $0 $0 + 1
${Loop}
${LoopWhile} $R9 > 0
${ElseIf} $0 != false
${InvalidValueError} [Launch]:WaitForOtherInstances $0
${EndIf}
${EndIf}
!endif
FunctionEnd
The above code makes use of the StdUtils plug-in which is the self proclaimed Swiss Army Knife for NSIS. For more information on this plugin, you can visit this page: http://nsis.sourceforge.net/StdUtils_plug-in
Footnote 1
I have added ${ConfigReads} `${CONFIG}` ExecAsAdmin= $0
as a means to check the user configuration file for the key ExecAsAdmin
for a true value. This is just a fail safe measure for the end-user who would still like for the application to run elevated even when we've set ExecAsUser
to be true..
Footnote 2
If you read the above code and came across Sleep ${Sleep}
, this is just another idea I used within my version of PAL where I define a number in milliseconds for an application if it has the ability to restart itself. For example, Notepad++ when it is installing/upgrading plugins. This little bit of code will make the launcher sleep for X amount of seconds before continuing on and checking if the main application's process has stopped.
Footnote 3 | Edit
I forgot to add a means to include this plugin. You'll notice I've added the same concept as I suggested on one of the open issues on the GitHub project. This snippet will add the plugin folder inside ../Other/Source/Plugins
which can hold all the necessary plugins needed for use within PAL. Here's the direct link to what I'm referring to: https://github.com/PortableApps/Launcher/issues/4#issuecomment-330439105