Unable to run command prompt commands using NSIS - nsis

I want to run a service using NSSM, doing so from Command Prompt (ran as administrator) works. Commands used in command prompt are:
# Command Prompt commands
C:\Windows\system32>cd C:\Users\D-002\Downloads\nssm-2.24\win64
C:\Users\D-002\Downloads\nssm-2.24\win64>
nssm install TestService "C:\Program Files (x86)\CodeBlocks\Testing Projects\TestServiceProgram\bin\Debug\TestServiceProgram.exe"
Service "TestService" installed successfully!
But I want to achieve same functionality using NSIS. Running following script doesn't create TestService.
# NSIS script
; name the installer
OutFile "Installer.exe"
; default section start; every NSIS script has at least one section.
Section
;nssm folder is placed in same folder where Installer.exe is created
ExecWait 'cd "$EXEDIR\nssm\win64"'
ExecWait 'nssm install TestService "$EXEDIR\TestServiceProgram.exe"'
; default section end
SectionEnd
As I have no prior knowledge of NSIS, if anybody could indicate, what I am doing wrong or missing ?

Check if the service is created into service list. Are created but not running?
If is created but not running remember that Services are executed with System32 as working directory and here you must place eventually config file.
You can install service with SimpleSC plugin (http://nsis.sourceforge.net/NSIS_Simple_Service_Plugin):
Here my code:
Section "Install Service"
SimpleSC::ExistsService "MyService" ;
MyService
pop $0
${If} $0 == "0" ;
{
SimpleSC::StopService "MyService"
DetailPrint "Service found"
}
${Endif}
DetailPrint "Installing My"
SimpleSC::InstallService "MyService" \
"My Service Description" \
16 \
2 \
"$ServiceFolder\MyService.exe" \
"" \
"" \
"" \
""
SimpleSC::SetServiceDescription "MyService" "MyService description"
DetailPrint "Installation of MyService completed"
SimpleSC::StartService MyService"
DetailPrint "Service started."
SectionEnd

Related

NSIS executing a system command

I'm trying to create a scheduled task with privileges in my NSIS script.
Using this command:
schtasks /create /ru "NT AUTHORITY\SYSTEM" /SC ONSTART /RL "HIGHEST" /TR "C:\Program Files (x86)\MyProgram\MyProgram.exe" /tn MyProgram.Kickstart
From cmd.exe with privileges I managed to do it, but now I need to let the NSIS script doing it.
Reading the documentation and the internet I've found this command:
; ........
Section
ExecShell "runas" "myprogram.bat"
SectionEnd
; ........
where "myprogram.bat" is the bat containing the command, but I've also tried to put the schtasks in it.
Currently it seems that no batch runs, even if I have this log:
Processing script file: "C:\Foo\prova.nsis"
OutFile: "C:\Foo\testnsis.exe"
Section: "TestFST"
ExecShell: runas: "C:\Foo\kickstart.bat" ""
SectionEnd
if I add 2> kickstart.log in bat and I execute it outside NSIS, i get the log filled as expected, but nothing from the script.
Also consider that, for sake of simplicity and testing purposes, I've wrote a very basic script launched from powershell:
# Powershell
makensis.exe /O"C:\Foo\prova.log" "C:\Foo\prova.nsis"
; NSIS
OutFile "C:\Foo\testnsis.exe"
Section TestFST
ExecShell "runas" "C:\Foo\kickstart.bat"
SectionEnd
and I might missing something, since I'm completely new to this.
What am I missing?
You should use full paths everywhere. When elevating the current directory is often set to the system32 directory and 2> kickstart.log would write there.
ExecShell works fine for me:
Section
InitPluginsDir
FileOpen $0 "$PluginsDir\Test.cmd" w
FileWrite $0 "#echo off$\r$\n"
FileWrite $0 "echo Hello World$\r$\n"
FileWrite $0 'call whoami /groups | find "1-5-32-544"$\r$\n'
FileWrite $0 'echo Log test string > "%temp%\test.log"$\r$\n'
FileWrite $0 "ping -n 42 localhost > nul$\r$\n"
FileClose $0
ExecShell "runas" "$PluginsDir\Test.cmd"
SectionEnd
That being said, the runas verb has some issues and if you know you are always going to perform elevated tasks then your installer should also request elevation (RequestExecutionLevel Admin).

nsExec::ExecToStack fails when running NSIS script tring to run DOS command

Please note that I am attempting to create a data file as part of my installation script. Here is what I am using:
# Create config.dat based on user`s previous selection
nsExec::ExecToStack '"$SYSDIR\cmd.exe" #echo ServerPort = 2003 > $INSTDIR\config.dat'
Pop $0 # return value/error/timeout
Pop $1 # printed text, up to ${NSIS_MAX_STRLEN}
DetailPrint '$SYSDIR\cmd.exe "#echo ServerPort = 2003 > $INSTDIR\config.dat" printed: $1'
DetailPrint ""
DetailPrint " Return value: $0"
DetailPrint ""
When I run the script, the above returns a 0, so I think it should have worked but when I check the installation directory I see that no config.dat file has been created.
Also, I have tried this command,
nsExec::ExecToStack '#echo ServerPort = 2003 > $INSTDIR\config.dat'
But when I use it the display prints:
Return value: error
Here are websites I have looked at but it is still not clear to me how to get nsExec working.
https://nsis.sourceforge.io/NsExec_plug-in
https://nsis.sourceforge.io/Docs/Chapter4.html
Does nsExec::ExecToStack is waiting the process to finish?(NSIS)
Exec vs ExecWait vs ExecShell vs nsExec::Exec vs nsExec::ExecToLog vs nsExec::ExecToStack vs ExecDos vs ExeCmd
Execute Command-Line Command from NSIS
Does anyone have any suggestions? TIA.
Please note that I have found the issue. I thought nsExec mainly worked with the command line, but you have to start with cmd:
nsExec::ExecToStack 'cmd /c "#echo ServerPort = 2003 > config.dat"'
For details please see:
Execute Command-Line Command from NSIS

How do I execute the app right after installation ... with arguments?

My installation EXE should unzip itself in a temp folder, then execute an app therein (with passing args), return and delete the temp folder again.
How do I write the nsi script?
It sounds to me like you are trying to create a portable application. Portable applications are always better when the original author adds support for it because it can handle registry and other configuration files correctly.
If you still want to create a launcher application you can do something like this:
OutFile "MyLauncher.exe"
RequestExecutionLevel User
SilentInstall Silent
SetCompressor LZMA
!include FileFunc.nsh
!insertmacro GetParameters
Section
${GetParameters} $1
InitPluginsDir
SetOutPath $PluginsDir
File "c:\myfiles\MyApp.exe"
File /r "c:\myfiles\otherfiles\*.*" ; If you need to include other files required by the application
ExecWait '"$PluginsDir\MyApp.exe" /param1 "pa ra m2" /param3 $1' $0 ; $1 contains the parameters passed to your launcher, remove it if you don't want to pass those arguments
SetErrorLevel $0
SetOutPath $Temp ; Don't lock $PluginsDir so it can be deleted automatically by the installer
SectionEnd
Answering my own question.
The required nsi script skeleton should look like this:
# The name of the installer (arbitrary)
Name "hello"
# The name of the installation file
OutFile "hello.exe"
# where put the installation - other options would be $TEMP, etc.
InstallDir $DESKTOP
RequestExecutionLevel user # no Windows UAC popup please!
SilentInstall silent # completely silent install
SetCompressor /SOLID /FINAL lzma # max compression for inst. file
# The stuff to install
Section ""
SetOutPath $INSTDIR # where to install (overwritable by user!)
File /r D:\...\... # where the install material lives
SectionEnd
# this function auto-runs after installation is fine
Function .onInstSuccess
# parameter are passed through via $CMDLINE
ExecWait '"$OUTDIR\hello.dist\hello.exe" $CMDLINE'
RMDir /r "$OUTDIR\hello.dist" # remove install folder again
FunctionEnd

Why my nsis script can not run command with execWait on Windows 10?

I want my nsis script to run the command line which is installed by my previous statements in my script successfully. But it always fails showing
C:\mypath\SystemMaitainer.exe' is not recognized as an internal or external command, operable program or batch file.
I put the related code after "install" section as below:
Section "install"
// Files copy statements
SectionEnd
Section "command"
nsExec::ExecToLog 'cmd.exe /c "$INSTDIR\SystemMaitainer.exe" -install'
Pop $0
DetailPrint ""
DetailPrint " Return value: $0"
DetailPrint ""
SectionEnd
How to fix my problem? Thanks! Why the statement about "nsEXec" always fails, but the command can run successfully in cmd ?
After investigation, my script can work, I should put the execwait command and the copy statements together as below:
Section "serverice"
ClearErrors
SetOutPath "$SYSDIR"
file "mycmd.exe"
ExecWait '"$SYSDIR\mycmd.exe" -option'
SectionEnd
But it worked perfectly on Windows 7, but it fails on Windows 10, ExecWait can't run successfully, and without the ret error message, please help me again! I am very appreciate guys who helped me!
That error message is coming from cmd.exe. SystemMaitainer is spelled incorrectly, perhaps that is the problem? Or maybe you disabled WOW64 redirection around the copy command but not the exec command?
You don't have to prefix the command with cmd /c if you are not doing stdout redirection.
$SysDir is special because there are two system32 directories on a 64-bit system.
You can access the 64-bit system32 directory in a 32-bit process with $WinDir\SysNative\ or with the macros in x64.nsh:
!include x64.nsh
${DisableX64FSRedirection}
ExecWait '"$SysDir\app.exe"'
${EnableX64FSRedirection}

NSIS: environment variable created doesn't work

I am creating a Env Variable and then appending it to the PATH variable in my NSIS installer script on Win7 - 64 bit.
Push "MyPath"
Push "D:\MyFolder\bin;D:\MyFolder\lib"
Call WriteEnvStr
Push "%MyPath%"
Call AddToPath
Now after installation I can see both the variable in cmd prompt
MyPath=D:\MyFolder\bin;D:\MyFolder\lib
Path=%MyPath%;<my existsing path>
But any exe/dll from are not found at run time.
If I run the cmd prompt as Administrator and then run exe, it runs fine.
It also works if I run exe directly as an Administrator.
Also interesting is that if I open Environment editor, double click on MyPath variable and click OK (without changing anything), my exe's run fine without running as Administrator.
And now if I check Path in cmd prompt, MyPath variable is substituted
MyPath=D:\MyFolder\bin;D:\MyFolder\lib
Path=D:\MyFolder\bin;D:\MyFolder\lib;<my existsing path>
I tried to add "Call EnvVarUpdate" after creating the env variable but it doesn't work.
I am using NSIS Unicode version 2.46.3
Your chances of adding/modifying the path without losing data in path by truncating it would be much greater by using the registry.
ReadRegStr $0 HKCU "Environment" Path
StrCpy $1 "D:\MyFolder\bin;D:\MyFolder\lib"
StrCpy $2 "$0;$1"
WriteRegStr HKCU "Environment" Path "$2"
If your system has an AUTOEXEC.BAT file then any PATH setting in AUTOEXEC.BAT will also be appended to the %PATH% environment variable. This is to provide compatibility with old installation routines which need to set the PATH. All other commands in AUTOEXEC.BAT are ignored however. And this is more or less obsolete anyway.
But we could just continue with your method however just try a different means of acomplishing your goal. I have not tested this but you can try something similar to this:
StrCpy $R0 "MYPATH"
StrCpy $R1 "D:\MyFolder\bin;D:\MyFolder\lib"
System::Call `Kernel32::SetEnvironmentVariable(t"$R0",t"$R1")`
Now include your new variable in the path like the following:
ReadEnvStr $R0 COMSPEC
ReadEnvStr $R1 MYPATH
ExecDos::Exec /TOSTACK `"$R0" /c "SetX PATH=%PATH%;$R1 -m"`
You can now easily change that one variable %MYPATH% at any time in the future and the PATH will reflect the new value.
${EnvVarUpdate} $0 "PATH" "A" "HKLM" "C:\Program Files\Java\jre6\bin"
StrCpy $R0 "$0"
System::Call 'Kernel32::SetEnvironmentVariableA(t, t) i("PATH", R0).r2'
ReadEnvStr $R0 "PATH"
ExecWait "$INSTDIR\tmp\batchfile.bat

Resources