Old 6th March 2020, 04:09   #1
flywire
Junior Member
 
Join Date: Mar 2020
Posts: 6
RequestExecutionLevel user or admin

Can a single Installation Context script allow install for all users (machine) or current user? eg C:\Program Files (x86) or %USERPROFILE%\AppData\Local\Programs under Win10-64bit? Would there be issues running it under other Win OSs?
flywire is offline   Reply With Quote
Old 6th March 2020, 11:03   #2
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,321
Linking to MSI documentation is a bit strange. If you want a MSI, use WiX.

You can also use "highest". You still need a way for the user to choose; a custom page and/or command line parameter.

If the userinfo plug-in says you are not admin then just install for the user.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 6th March 2020, 11:50   #3
flywire
Junior Member
 
Join Date: Mar 2020
Posts: 6
I must have explained something wrong, it is an NSIS app with admin access.
flywire is offline   Reply With Quote
Old 7th March 2020, 02:45   #4
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,321
You can't use "RequestExecutionLevel admin" if you want non-admins to be able to install, use highest or user.

You should not mix HKCU with HKLM & $PROGRAMFILES.

And your version check is strange. Non-admin programs should work on 2000 & XP. And even if not, you forgot about 2003. Your check should be for AtLeastVista if you are thinking about UAC.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 7th March 2020, 04:01   #5
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,321
PHP Code:

!include LogicLib.nsh
RequestExecutionLevel highest
#InstallDir "" ; Don't set this so we can detect /D


Var IsAdminMode
!macro SetAdminMode
StrCpy $IsAdminMode 1
SetShellVarContext All
${IfThen$InstDir == "" ${|} StrCpy $InstDir "$Programfiles\$(^Name)" ${|}
!
macroend
!macro SetUserMode
StrCpy $IsAdminMode 0
SetShellVarContext Current
${IfThen$InstDir == "" ${|} StrCpy $InstDir "$LocalAppData\Programs\$(^Name)" ${|}
!
macroend

Function .onInit
UserInfo
::GetAccountType
Pop 
$0
${IfThen} $!= "Admin" ${|} Goto setmode_currentuser ${|}

!
insertmacro SetAdminMode
Goto finalize_mode

setmode_currentuser
:
!
insertmacro SetUserMode

finalize_mode
:
FunctionEnd

Function un.onInit
FileOpen 
$"$ExePathr
FileSeek 
$-1 END
FileReadByte 
$$1
FileClose 
$0
UserInfo
::GetAccountType
Pop 
$0
${If} $<> 0
    
!insertmacro SetAdminMode
    
${If} $!= "Admin"
        
MessageBox MB_ICONSTOP "You must be an administrator to uninstall!"
        
Quit
    
${EndIf}
${Else}
    !
insertmacro SetUserMode
${EndIf}
FunctionEnd

Page Directory
Page InstFiles

Section
SetOutPath $InstDir
WriteUninstaller 
"$InstDir\Uninst.exe"
FileOpen $"$InstDir\Uninst.exe" a
FileSeek 
$0 0 END
FileWriteByte 
$0 $IsAdminMode Store the mode
FileClose 
$0
;WriteRegStr ShCtx "Software\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" ....
;
File myapp.exe
SectionEnd

Section Uninstall
;Delete "$InstDir\myapp.exe"
Delete "$InstDir\Uninst.exe"
RMDir $InstDir
DeleteRegKey ShCtx 
"Software\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
SectionEnd 

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 8th March 2020, 23:44   #6
flywire
Junior Member
 
Join Date: Mar 2020
Posts: 6
@Anders Thank you for your help but I don't understand it.

I appreciate your advice that NSIS will do both user and admin installs and there are issues that need fixing so your other advice is a bonus. The installer is in an open source project written 5 years ago and updated by a different user each year all long gone, probably linux users with little interest in Windows.

The NSIS Menu is confusing and eventually I noticed the wiki Simple tutorials link (which I tweaked to make a little clearer). It clearly explains the process for compiling scripts and got me started.
  1. I assume I need to rework the script to include most of the code you provided (?)
  2. There are no HKCU commands in the script so I don't understand that comment but I note the code you provided fixes $PROGRAMFILES
  3. I don't know what comprises the version check or why it is required
flywire is offline   Reply With Quote
Old 9th March 2020, 11:31   #7
flywire
Junior Member
 
Join Date: Mar 2020
Posts: 6
Quote:
Originally Posted by flywire View Post
2. There are no HKCU commands in the script ...
Completely wrong. I meant no HKLM commands.
flywire is offline   Reply With Quote
Old 9th March 2020, 01:38   #8
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,321
Yes. The important parts are the init functions, the uninstaller "tag" and using ShCtx.

The github code you linked to clearly reads and writes to HKCU.

The version check tries the enforce admin rights on 2000 and XP but it is flawed because:
A) It forgot about NT4 and 2003
B) UAC can be turned off on Vista+
C) Users can bypass UAC and run it as non-admin

Version check should ideally use AtMost/AtLeast but that script should not check the version at all, treat all versions the same.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 9th March 2020, 11:25   #9
flywire
Junior Member
 
Join Date: Mar 2020
Posts: 6
Quote:
Originally Posted by Anders View Post
The github code you linked to clearly reads and writes to HKCU.
OK. Can you recommend a better template to start with other than the NSIS\Examples\Modern UI\Basic.nsi it is based on?
flywire is offline   Reply With Quote
Old 9th March 2020, 11:52   #10
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,321
I'll try to explain again.

RequestExecutionLevel admin+HKLM+$ProgramFiles is a set (All users/machine install).

RequestExecutionLevel user+HKCU+$AppData/$LocalAppData is a set (Single user install).

You should not mix and match these. To choose a set at run-time you must use ShCtx instead of HKxx and manually set $InstDir.

Mixing RequestExecutionLevel admin with HKCU creates a installer that writes to the wrong HKCU when a non-admin runs your installer with "over-the-shoulder" UAC elevation. (https://docs.microsoft.com/en-us/win...ccount-control)

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 29th March 2020, 04:24   #11
flywire
Junior Member
 
Join Date: Mar 2020
Posts: 6
Testing uses the NSIS\Examples\Modern UI\Basc.nsi example since it was used by the original application and should be useful for others following this thread.

In summary, the key issue is the installer needs to change the registry but a user only has access to HKEY_CURRENT_USER (HKCU) and changing HKEY_LOCAL_MACHINE (HKLM) requires admin access. As noted above to choose install type at run-time:
Code tested is at the bottom of this post.

Test Results:

Quote:
To find out if your account has administrator privilege follow the steps below:

* Press Windows + R.
* Type netplwiz then hit Enter.
* Verify from the pop-up window if the account your using has administrator privilege.
Admin user:

"Do you want to allow this app from an unknown publisher to make changes to your device?"
N - Installer terminates, Y - Installer runs
Destination: C:\Program Files (x86)\Modern UI Test

Output Folder: C:\Program Files (x86)\Modern UI Test - Verified
Created uninstaller: C:\Program Files (x86)\Modern UI TestUninstall.exe - Verified

Registry: Computer\HKEY_USERS\S-1-5-21-293778308-4012132540-2240235571-1001\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Compatibility Assistant\Store

Uninstall removes installation as above.

Comment:

* No option for Admin user to just install for current user
* Non-admin install not tested


PHP Code:
;NSIS Modern User Interface
;
Basic Example Script
;Written by Joost Verburg
;Modified by Anders and flywire

;--------------------------------
;Include 
Modern UI

  
!include "MUI2.nsh"
  
!include LogicLib.nsh

;--------------------------------
;
General

  
;Name and file
  Name 
"Modern UI Test"
  
OutFile "BasicCtx.exe"
  
Unicode True

  
;Default installation folder
  
# InstallDir "$LOCALAPPDATA\Modern UI Test"
  #InstallDir "" ; Don't set this so we can detect /D
  
  
;Get installation folder from registry if available
  
# InstallDirRegKey HKLM "Software\Modern UI Test" ""

  
;Request application privileges for Windows Vista
  
# RequestExecutionLevel user
  
RequestExecutionLevel highest


  
Var IsAdminMode
  
!macro SetAdminMode
  StrCpy $IsAdminMode 1
  SetShellVarContext All
  
${IfThen$InstDir == "" ${|} StrCpy $InstDir "$Programfiles\$(^Name)" ${|}
  !
macroend
  
!macro SetUserMode
  StrCpy $IsAdminMode 0
  SetShellVarContext Current
  
${IfThen$InstDir == "" ${|} StrCpy $InstDir "$LocalAppData\Programs\$(^Name)" ${|}
  !
macroend

;--------------------------------
;Interface 
Settings

  
!define MUI_ABORTWARNING

;--------------------------------
;
Pages

  
!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt"
  
!insertmacro MUI_PAGE_COMPONENTS
  
!insertmacro MUI_PAGE_DIRECTORY
  
!insertmacro MUI_PAGE_INSTFILES
  
  
!insertmacro MUI_UNPAGE_CONFIRM
  
!insertmacro MUI_UNPAGE_INSTFILES
  
;--------------------------------
;
Languages
 
  
!insertmacro MUI_LANGUAGE "English"

;--------------------------------
;
Installer Sections

Section 
"Dummy Section" SecDummy

  SetOutPath 
"$INSTDIR"

  
;ADD YOUR OWN FILES HERE...

  ;
Store installation folder
  
# WriteRegStr HKCU "Software\Modern UI Test" "" $INSTDIR

  
;Create uninstaller
  WriteUninstaller 
"$INSTDIR\Uninstall.exe"
  
FileOpen $"$InstDir\Uninstall.exe" a
  FileSeek 
$0 0 END
  FileWriteByte 
$0 $IsAdminMode Store the mode inside the uninstaller
  FileClose 
$0

  WriteRegStr ShCtx 
"Software\$(^Name)" "" $INSTDIR
  
;File myapp.exe

  

SectionEnd

;--------------------------------
;
Descriptions

  
;Language strings
  LangString DESC_SecDummy 
${LANG_ENGLISH"A test section."

  
;Assign language strings to sections
  
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
    
!insertmacro MUI_DESCRIPTION_TEXT ${SecDummy} $(DESC_SecDummy)
  !
insertmacro MUI_FUNCTION_DESCRIPTION_END

;--------------------------------
;
Uninstaller Section

Section 
"Uninstall"

  
;ADD YOUR OWN FILES HERE...

  
Delete "$INSTDIR\Uninstall.exe"

  
RMDir "$INSTDIR"

  
#DeleteRegKey /ifempty HKCU "Software\Modern UI Test"
  
DeleteRegKey /ifempty ShCtx "Software\$(^Name)"

SectionEnd


Function .onInit
UserInfo
::GetAccountType
Pop 
$0
${IfThen} $!= "Admin" ${|} Goto setmode_currentuser ${|}

!
insertmacro SetAdminMode
Goto finalize_mode

setmode_currentuser
:
!
insertmacro SetUserMode

finalize_mode
:
FunctionEnd

Function un.onInit
FileOpen 
$"$ExePathr
FileSeek 
$-1 END
FileReadByte 
$$1
FileClose 
$0
UserInfo
::GetAccountType
Pop 
$0
${If} $<> 0
    
!insertmacro SetAdminMode
    
${If} $!= "Admin"
        
MessageBox MB_ICONSTOP "You must be an administrator to uninstall!"
        
Quit
    
${EndIf}
${Else}
    !
insertmacro SetUserMode
${EndIf}
FunctionEnd 
flywire is offline   Reply With Quote
Old 29th March 2020, 21:33   #12
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,321
The code as posted does not let administrators choose, it installs for everyone if admin and for a single user if not admin (code in .onInit).

Since you are using the MUI you can dump this code and use MultiUser.nsh instead if you wish, it has a selection page. Or you can make your own custom page.

(I edited your code a bit since it had a major issue with the order of WriteUninstaller and FileWriteByte)

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Tags
requestexecutionlevel

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump