NSIS uninstaller privileges according to installer - nsis

I have an NSIS installer for an application, which can be run as normal user. But if the user wants to install into the "Program Files" directory, it can still be accomplished by starting the installer with administrator privileges.
Now I have the problem, that the uninstaller is started with user privileges by default, even if the installation took place as administrator. This causes the uninstallation to silently fail. Even worse: It even states that the uninstall process was successful without being able to delete any files.
My question is: Is it possible to create an uninstaller during the installation, which requires (or better: requests itself with) the same privileges as the installation process?

You would have to implement this check yourself. You can check if you are admin in the installer with the UserInfo plugin and then store the result in a .ini, the registry or append the info to the uninstaller.exe:
InstallDir $temp\instdir
Section
UserInfo::GetAccountType
Pop $0
StrCmp $0 "Admin" 0 +2
StrCpy $0 1
IntOp $0 $0 & 1 ; $0 is now 1 if admin or 0 if not
SetOutPath $InstDir
WriteUninstaller "$InstDir\Uninstall.exe"
FileOpen $1 "$InstDir\Uninstall.exe" a
FileSeek $1 0 END
FileWriteByte $1 $0
FileClose $1
SectionEnd
Section Uninstall
FileOpen $1 "$ExePath" r
FileSeek $1 -1 END
FileReadByte $1 $0
FileClose $1
DetailPrint "Installer was admin: $0"
SectionEnd

Related

Installation is failing when installing the application using NSIS to create and control the service

My requirement is, when installing the application using NSIS the service should be installed and controlled (Start and Stop)
For this, first i downloaded "NSIS_Simple_Service_Plugin_1.30" and placed SimpleSC.dll in the "x86-ansi" directory.
I wrote the below code Under "Section"
;InstallServices:
SimpleSC::InstallService "testserv" "Test Service Testtwo" "16" "2" "E:\Source\Release\testserv.exe" "" "" ""
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 +3
MessageBox MB_OK|MB_ICONSTOP "testserv installation failed: could not create service."
Abort
SimpleSC::SetServiceDescription "testserv" "Test Project service."
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; We don't care about the result.
; Start a service using NSIS Simple Service Plugin
SimpleSC::StartService "testserv" ""
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 +3
MessageBox MB_OK|MB_ICONSTOP "testserv installation failed: could not start service."
Abort
When i am testing the installer, it is showing the message "testserv installation failed: could not create service" from the MessageBox i kept.
Is it the correct place ("section") to write this code snippet or any other place like .OnInit?
And also while installing the service at the service name field, do we need to give "testserv" or "testserv.exe"
SimpleSc::InstallService "testserv"
or
SimpleSc::TestInstallService "testserv.exe"
which one is correct?
Below is the complete code:
; ServiceTest.nsi
;
;
; It will install ServiceTest.nsi into a directory that the user selects.
;--------------------------------
; The name of the installer in the path C:\Program Files\Registry
Name "ServiceTest"
; The file to write in the path E:\Source\NULLSOFT\src
OutFile "ServiceTest.exe"
; The default installation directory in the path C:\Program Files\ServiceTest
InstallDir $PROGRAMFILES\ServiceTest
; Registry key to check for directory (so if you install again, it will
; overwrite the old one automatically) It shows the path the path C:\Program Files\ServiceTest
InstallDirRegKey HKLM "Software\ServiceTest" "Install_Dir"
; Request application privileges for Windows Vista
; Below line is to check the administrative permissions
RequestExecutionLevel admin
; Below is the include file to check the conditions (If and else)
!include LogicLib.nsh
;--------------------------------
; Pages
Page components
Page directory
Page instfiles
UninstPage uninstConfirm
UninstPage instfiles
;--------------------------------
;--------------------------------
;Installer Functions
Function .onInit
UserInfo::GetAccountType
pop $0
${If} $0 != "admin"
MessageBox mb_iconstop "Administrator rights required!"
SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED
Quit
${Else}
MessageBox MB_OK "User is having Administrative Permissions"
${EndIf}
FunctionEnd
;--------------------------------
; The stuff to install
Section "ServiceTest (required)"
SectionIn RO
; Set output path to the installation directory. Here is the path C:\Program Files\ServiceTest
SetOutPath $INSTDIR
; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\ServiceTest "Install_Dir" "$INSTDIR"
WriteRegStr HKLM SOFTWARE\ServiceTest\Dialog "TestDlg" "0"
; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\ServiceTest" "DisplayName" "ServiceTest"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\ServiceTest" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\ServiceTest" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\ServiceTest" "NoRepair" 1
WriteUninstaller "uninstall.exe"
;InstallServices:
SimpleSC::InstallService "testserv" "Test Service Testtwo" "16" "2" "E:\Source\testserv\Release\testserv.exe" "" "" ""
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 +3
MessageBox MB_OK|MB_ICONSTOP "testserv installation failed: could not create service."
Abort
SimpleSC::SetServiceDescription "testserv" "Test service."
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; We don't care about the result.
; Start a service using NSIS Simple Service Plugin
SimpleSC::StartService "tetserv" ""
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 +3
MessageBox MB_OK|MB_ICONSTOP "testserv installation failed: could not start service."
Abort
SectionEnd
; Optional section (can be disabled by the user)
Section "Start Menu Shortcuts"
CreateDirectory "$INSTDIR\ServiceTest"
CreateShortcut "$INSTDIR\ServiceTest\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
CreateShortcut "$INSTDIR\ServiceTest\ServiceTest (MakeNSISW).lnk" "$INSTDIR\ServiceTest.nsi" "" "$INSTDIR\ServiceTest.nsi" 0
SectionEnd
;--------------------------------
; Uninstaller
Section "Uninstall"
; Remove registry keys
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\ServiceTest"
DeleteRegKey HKLM SOFTWARE\ServiceTest
; Remove files and uninstaller
Delete $INSTDIR\ServiceTest.nsi
Delete $INSTDIR\uninstall.exe
; Remove shortcuts, if any
Delete "$INSTDIR\ServiceTest\*.*"
; Remove directories used
RMDir "$INSTDIR\ServiceTest"
RMDir "$INSTDIR"
; To Uninstall the Service
; Stop the service using NSIS Simple Service Plugin
SimpleSC::ExistsService "testserv"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 +1
; Stop the service using NSIS Simple Service Plugin
SimpleSC::StopService "tesserv"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 +3
MessageBox MB_OK|MB_ICONSTOP "testserv uninstallation failed: could not stop service."
Abort
; Stop the service using NSIS Simple Service Plugin
SimpleSC::RemoveService "testserv"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 +3
MessageBox MB_OK|MB_ICONSTOP "testserv uninstallation failed: could not remove service."
Abort
SectionEnd
Is it the correct way to check "ExistsService", "StopService", and "RemoveService" in "Uninstall" section?
Please help me to resolve the issue and provide your thoughts to install and use the service.
The first parameter is the internal name of the service. It does not need a .exe suffix.
You problem is probably "E:\Code\PCPE\mainserv\Release\mainserv.exe" which is a path on your computer. It needs to be the path to the installed service on the end-users machine. It also helps if you include the error code in your message box so you can know for sure what the error actually is:
!include LogicLib.nsh
Section
SetOutPath $InstDir
File "E:\Code\PCPE\mainserv\Release\mainserv.exe"
SimpleSC::InstallService "mainserv" "UPS Service Testtwo" "16" "2" '"$InstDir\mainserv.exe"' "" "" ""
Pop $0
${If} $0 <> 0
MessageBox MB_ICONSTOP "InstallService failed, error $0"
Abort
${EndIf}
...
SectionEnd
The rest of your code looks OK but I would recommend that you use LogicLib.nsh instead of jumps with offset.

Calling another program in nsis silent installation

I already have a nsis installer for my software. For supporting registration in silent installer (we have written complex logic in code rather than manipulating registry via nsis), i created an exe which accepts 2 parameters: RegName and RegKey for registration. Now I want to call this exe file with two parameters in silent installation and this call has to be optional and will depend if user has passed the two parameters.
So requirement boils down to :
-- Only process the key and registration name in silent installation
-- call my exe if the overall installation went successfull
OutFile "myinstaller.exe"
RequestExecutionLevel user
!include LogicLib.nsh
!include FileFunc.nsh
Function CheckRegistryParameters
${GetParameters} $0
${GetOptions} "$0" "/RegKey" $1
${GetOptions} "$0" "/RegName" $2
${If} $1 != ""
${AndIf} $2 != ""
WriteRegStr HKCU "Software\Test\$1" "Name" "$2"
Exec '"yourapplication.exe" "$1" "$2"'
${EndIf}
FunctionEnd
Section
${If} ${Silent}
Call CheckRegistryParameters
${EndIf}
SectionEnd
and run as myinstaller.exe /S /RegKey "Hello" /RegName "World"

NSIS roll-back installer if ExecWait command gets a specific return code

I'm currently using the following script to install drivers along with my application:
!macro customInstall
ExecWait '"$INSTDIR\resources\DPInst.exe" /sw'
!macroend
However, if DPInst returns >= 0x80010000, this means one or more of the driver installs has failed so I need to roll-back the installation and quit. Any idea how I would do this?
ExecWait can store the process exit code in the 2nd parameter. Not much you can do to roll it back, it is best just to do it early in the install phase:
!include LogicLib.nsh
Section
SetOutPath "$instdir\resources"
File "whatever\DPInst.exe"
ExecWait '"$INSTDIR\resources\DPInst.exe" /sw' $0
${If} $0 U>= 0x80010000
Delete "$INSTDIR\resources\DPInst.exe"
RMDir $instdir\resources
RMDir $instdir
MessageBox mb_iconstop "Error blah blah"
Abort
${EndIf}
SectionEnd

Making installer/reinstaller in NSIS

I need this routine - if RegKey with Installation Path is presented, we must to stop executed application (if executed), start Uninstaller silently (if uninstaller is not found - just delete all files in the directory) and set INSTDIR to value from Registry.
If RegKEy with Installation Path is not exists - start normal installation.
; Try to read Install Path from Reg
ReadRegStr $0 HKCU "Software\TelnetTray" "Path"
; Uninstall first if app installed
${If} $0 != ""
!define INSTDIR $0
; Try to stop app if executed
Stop "$INSTDIR\app.exe"
; Try to uninstall
${If} ${FIleExists} "$INSTDIR\uninst.exe"
ExecWait "$INSTDIR\uninst.exe /S"
; Or just delete all files in INSTDIR
${Else}
Delete "$INSTDIR\*"
${EndIf}
${EndIf}
You almost got it
; Try to read Install Path from Reg
ReadRegStr $0 HKCU "Software\TelnetTray" "Path"
; Uninstall first if app installed
${If} $0 != ""
StrCpy $INSTDIR $0
; Try to stop app if executed
${nsProcess::CloseProcess} "$INSTDIR\app.exe" $R0
; Try to uninstall
${If} ${FIleExists} "$INSTDIR\uninst.exe"
ExecWait "$INSTDIR\uninst.exe /S"
; Or just delete all files in INSTDIR
${Else}
RMDir /r "$INSTDIR"
${EndIf}
${EndIf}

NSIS AccessControl Plugin disable access to directory for all except Admins and System

I just read bunch of answers about setting permissions to directory by NSIS AccessControl plugin, but all those only show basic usage copy pasted from plugin site... It only shows cases ALL or NOTHING... but how do I disable ALL permissions to directory for everyone except System and Administrators?
AccessControl::DisableFileInheritance "$temp\test.tmp"
Pop $0
DetailPrint $0
AccessControl::ClearOnFile "$temp\test.tmp" "(S-1-5-18)" "FullAccess"
Pop $0
DetailPrint $0
AccessControl::SetOnFile "$temp\test.tmp" "(S-1-5-32-544)" "FullAccess"
Pop $0
DetailPrint $0
This might not be enough, you should probably also use SetFileOwner and maybe SetFileGroup...

Resources