How to write a .bat file in nsis script - nsis

$INSTDIR\DOWNPRINT\runRestart.bat" "TEXT" "#ECHO OFFdel $INSTDIR\DOWNPRINT\process.txtwmic process get processid,name,commandline /format:csv | findstr "runPosiboltprint.bat" | findstr /V "findstr" > $INSTDIR\DOWNPRINT\process.txt(for /f "tokens=3,* delims=," %%a in($INSTDIR\DOWNPRINT\process.txt) do #echo %%b) >$INSTDIR\DOWNPRINT\pid.txtcd $INSTDIR\DOWNPRINT\SET /P A= < $INSTDIR\DOWNPRINT\pid.txttaskkill.exe /F /PID %A%$INSTDIR\Java\bin\java.exe -jar $INSTDIR\DOWNPRINT\printer.jar
this is my batch script
i already tried FileWrite and WriteIniStr. But both are throwing an error like
WriteIniStr expects 4 parameters, got 28. and FileWrite expects 4 parameters, got 28.
ANYBODY PLEASE HELP ME!

You need to quote the string when using FileWrite:
Section
InitPluginsDir
FileOpen $0 "$pluginsdir\myscript.bat" w
FileWrite $0 '#echo off$\r$\n'
FileWrite $0 'echo Hello world$\r$\n'
FileWrite $0 'echo foo "bar" | find /I "FOO" > $pluginsdir\temp.txt $\r$\n'
FileClose $0
ReadEnvStr $0 COMSPEC
nsExec::Exec '"$0" /c "$pluginsdir\myscript.bat"' ; Run the batch with a hidden window. Use ExecWait if you want a visible window
Pop $0
DetailPrint "Returned $0"
SectionEnd

Related

NSIS Exec not executing and gives return code of 0

I'm running the script shown below and neither the directory nor the logical link are being created. I'm not sure what I'm doing wrong. Each call returns a code of 0 (zero). I'm using the information available here
Execute Command-Line Command from NSIS
https://nsis.sourceforge.io/Docs/Chapter4.html
RequestExecutionLevel admin
# includes
!include .\PrependEnv.nsh
# definitions
Outfile "007-exec-examples.exe"
InstallDir "C:\temp\nsis-examples\007-exe-examples"
Page Directory
Page InstFiles
# section to copy files and manipulate env variable
Section
# copy files
DetailPrint ""
DetailPrint "Copying files to $InstDir..."
DetailPrint ""
SetOutPath "$InstDir\resources"
File /a /r "resources\"
# create a dir
DetailPrint ""
DetailPrint "Making dir $InstDir"
Exec 'mkdir $InstDir\delete_me'
Pop $0
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
# create a logical link
DetailPrint ""
DetailPrint "Creating logical link as C:\_YES to $InstDir\delete_me."
Exec 'mklink /D $InstDir\_MY_LINK $InstDir\delete_me'
Pop $0
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
SectionEnd
--- EDIT ----------------------------
This also fails but does give a indication that an error occurred.
# ---
#
# This script tries to create a dir and a logical link.
#
# ---
RequestExecutionLevel admin
# includes
!include .\PrependEnv.nsh
# definitions
Outfile "008-exec-examples.exe"
InstallDir "C:\temp\nsis-examples\008-exe-examples"
ShowInstDetails show
Page Directory
Page InstFiles
# section to copy files and manipulate env variable
Section
# copy files
DetailPrint ""
DetailPrint "Copying files to $InstDir..."
DetailPrint ""
SetOutPath "$InstDir\resources"
File /a /r "resources\"
# create a dir
DetailPrint ""
DetailPrint "Making dir $InstDir\delete_me"
nsExec::ExecToStack 'mkdir $InstDir\delete_me'
Pop $0
Pop $1
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
DetailPrint "$1"
# create a logical link
DetailPrint ""
DetailPrint "Creating logical link as $InstDir\_MY_LINK to $InstDir\delete_me."
nsExec::ExecToStack 'mklink /D $InstDir\_MY_LINK $InstDir\delete_me'
Pop $0
Pop $1
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
DetailPrint "$1"
SectionEnd
--- EDIT --------------------------------
Here's a full working example based on the accepted answer. This example creates a directory, a shortcut, and a link.
# ---
#
# This script tries to create a dir and a logical link.
#
# ---
RequestExecutionLevel admin
# includes
!include .\PrependEnv.nsh
# definitions
Outfile "009-exec-examples.exe"
InstallDir "C:\temp\nsis-examples\009-exe-examples"
ShowInstDetails show
Page Directory
Page InstFiles
# section to copy files and manipulate env variable
Section
# copy files
DetailPrint ""
DetailPrint "Copying files to $InstDir..."
DetailPrint ""
SetOutPath "$InstDir\resources"
File /a /r "resources\"
# create a dir
DetailPrint ""
DetailPrint "Making dir $InstDir\delete_me"
CreateDirectory $InstDir\delete_me
Pop $0
Pop $1
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
DetailPrint "$1"
# create a short cut
DetailPrint ""
DetailPrint "Creating SHORTCUT as $InstDir\_MY_SHORTCUT to $InstDir\delete_me."
CreateShortCut $InstDir\_MY_SHORTCUT.lnk $InstDir\delete_me
Pop $0
Pop $1
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
DetailPrint "$1"
# create a logical link
DetailPrint ""
DetailPrint "Creating LINK as $InstDir\_MY_SHORTCUT to $InstDir\delete_me."
nsExec::ExecToStack 'cmd.exe /C mklink /D $InstDir\_MY_LINK $InstDir\delete_me'
Pop $0
Pop $1
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
DetailPrint "$1"
SectionEnd
For a directory, just use CreateDirectory. mklink is an internal command inside cmd.exe, you would have to execute cmd.exe /C mklink /D "c:\link" "c:\target".
Alternatively, call the API directly:
Section
!define /IfNDef SYMBOLIC_LINK_FLAG_DIRECTORY 1
System::Call 'KERNEL32::CreateSymbolicLink(t "c:\link", t "c:\target", i ${SYMBOLIC_LINK_FLAG_DIRECTORY})b.r0
DetailPrint Success=$0
SectionEnd
This worked to create a short cut (not a logical link):
# ---
#
# This script tries to create a dir and a logical link.
#
# ---
RequestExecutionLevel admin
# includes
!include .\PrependEnv.nsh
# definitions
Outfile "009-exec-examples.exe"
InstallDir "C:\temp\nsis-examples\009-exe-examples"
ShowInstDetails show
Page Directory
Page InstFiles
# section to copy files and manipulate env variable
Section
# copy files
DetailPrint ""
DetailPrint "Copying files to $InstDir..."
DetailPrint ""
SetOutPath "$InstDir\resources"
File /a /r "resources\"
# create a dir
DetailPrint ""
DetailPrint "Making dir $InstDir\delete_me"
CreateDirectory $InstDir\delete_me'
Pop $0
Pop $1
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
DetailPrint "$1"
# create a logical link
DetailPrint ""
DetailPrint "Creating logical link as $InstDir\_MY_LINK to $InstDir\delete_me."
CreateShortCut $InstDir\_MY_LINK.lnk $InstDir\delete_me'
Pop $0
Pop $1
DetailPrint "RegPrependString:Error=$0 (Should be 0)"
DetailPrint "$1"
SectionEnd

How can I use the following script?

I want to delete all files except the Bookmarks file from the Default folder. But the following code does not work. I know I should use the Batch file, but is there a way to use the code below? Thank you for any help
ExecWait '"$SYSDIR\cmd.exe" /c "SET "sourcedir=$LOCALAPPDATA\Google\Default" & SET "keepfile=Bookmarks" & FOR %a IN ("%sourcedir%*") DO IF /i NOT "%~nxa"=="%keepfile%" DEL "%a""'
Section "Prepare example"
SetOutPath "$LOCALAPPDATA\Google\Default"
SetOverwrite off
File "/oname=$outdir\Bookmarks" "${__FILE__}"
File "/oname=$outdir\Blah" "${__FILE__}"
File "/oname=$outdir\Footmarks" "${__FILE__}"
SectionEnd
!include LogicLib.nsh
Section
StrCpy $2 "$LOCALAPPDATA\Google\Default"
FindFirst $0 $1 "$2\*"
loop:
StrCmp $1 "" done
StrCmp $1 . next
StrCmp $1 .. next
${If} $1 != "Bookmarks"
Delete "$2\$1"
${EndIf}
next:
FindNext $0 $1
Goto loop
done:
FindClose $0
SectionEnd

How to prefix log entries generated from NSIS exe with current date and time without overwriting registers?

I want to write timestamps at the start of each line entered into a log during the run of an NSIS (Nullsoft) .exe program.
It appears the only valid pattern to call the GetTime function is:
${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6
This results in overwriting the registers ($0, $1, etc.) in the calling .nsh files. Is there a way to prevent this?
For example:
The global_defines.nsh contains something like this:
!macro WriteLog text
...
FileWrite $mylogfile '${text}'
${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6
FileWrite $mylogfile "$2-$1-$0 $4:$5:$6 '${text}'"
...
and the calling .nsh file contains something like this:
StrCpy $1 'run_this_script'
!insertmacro WriteLog "About to run: $1"
ExecDos::exec /TOWINDOW $1
pop $0
!insertmacro WriteLog "script run returned $0"
This results in $1 getting set to the month value set in the macro.
A separate posting:
https://stackoverflow.com/a/19622151/6388369
shows using $year, etc., but this does not compile.
$year is a custom variable:
Var year
Section
${GetTime} ... $year ...
FileWrite ...
SectionEnd
The other alternative is to save/restore the old data if you need to preserve it (which you usually need to do in helper macros):
Section
Push $0
Push $1
Push ...
${GetTime} ... $0 $1 ...
FileWrite ...
Pop ...
Pop $1
Pop $0
SectionEnd

NSIS Inetc get: can I make the downloaded file a variable?

The code is working when I have File_1234.exe added there. But the file name changes and download.php redirects to the exe. So instead of having a fixed file name there, I would like to have a code where i don't need to specify file name.
Is it possible to replace the first File_1234.exe with code to download whatever file the URL gives, and therefore to replace the second File_1234.exe with code that would run (ExecShell) this downloaded file?? Thanks
The code itself is here:
Section "File"
inetc::get "http://example.com/download.php" "$pluginsdir\File_1234.exe"
Pop $0
DetailPrint "Result: $R0"
ExecShell "" '"$pluginsdir\File_1234.exe"'
SectionEnd
INetC does not have a flag that passes the INTERNET_FLAG_NO_AUTO_REDIRECT flag to WinInet so there is no way to do a head request and find the location when the server returns a 30x redirection code.
If you can modify download.php to just return the final URL as a small text file when a special parameter is present then you can make two GET requests, the first to get the name and the second to do the main download:
Section
InitPluginsDir
StrCpy $0 "http://example.com/download.php?fileid=1234"
inetc::get /SILENT "$0&locationonly=1" "$PluginsDir\location.txt" /END
FileOpen $1 "$PluginsDir\location.txt" R
FileRead $1 $2
FileClose $1
StrLen $1 $2
loop:
IntOp $1 $1 - 1
StrCpy $3 $2 1 $1
StrCmp $3 '/' 0 +4
IntOp $1 $1 + 1
StrCpy $3 $2 "" $1
Goto +2
StrCmp $3 "" 0 loop
StrCmp $3 "" nofilename
inetc::get "$0" "$PluginsDir\$3" /END
Goto done
nofilename:
MessageBox mb_iconstop "Unable to parse filename from $2"
done:
SectionEnd
This example assumes that http://example.com/download.php?fileid=1234 would download the file but http://example.com/download.php?fileid=1234&&locationonly=1 would only return a URL like http://example.com/myfiles/whatever.exe
This is a 5 year later answer to help who ever might want to know how to get inetc::get output into a variable ;)
Obviously you found a solution since then... anyway:
inetc::get has a nice option /TOSTACK that does this.
Here's how on your example:
!include LogicLib.nsh
Section "File"
inetc::get /TOSTACK "http://example.com/download.php" ""
Pop $0
DetailPrint "Result: $0"
${If} $0 == 'OK'
Pop $0
StrCpy $filename $0
inetc::get /TOSTACK "http://example.com/$filename" "$PluginsDir\$filename"
Pop $0
${If} $0 == 'OK'
ExecShell "" '"$pluginsdir\$filename"'
${Else}
MessageBox MB_OK "Cannot download file $filename"
${EndIf}
${Else}
MessageBox MB_OK "Cannot fetch filename to download"
${EndIf}
SectionEnd
This is possible if your "http://example.com/download.php" returns URL of file to download.
What I mean: download.php returns URL as text ("http://example.com/file_12345.exe").
1) This text is downloaded with inetc to some local file and read into variable.
2) Use Inetc to download the file from URL (specified in variable) again as a resulting .exe file.
Is this acceptable for you?

How can I search for a string in a txt file?

Is there some way that I can search in a example.txt file for a string example?
I tried Fileread and Fileseek but it is not working yet... later I'd like to write to the file, that's why I use FileOpen with the a append attribute:
FileOpen $4 "$SYSDIR\drivers\etc\hosts" a
FileSeek $4 0 SET
FileRead $4 $1
${If} $1 != "example"
Strcmp $1 "example" end 0
Or can I walk through the file with While? But when does the file end?
Update
!define IP_AND_DISPATCHER "30.0.0.0 dispatcher"
FileOpen $0 "$SYSDIR\drivers\etc\hosts" a
loop:
FileRead $0 $2
IfErrors done
Messagebox MB_OK "$2"
StrCmp $2 "${IP_AND_DISPATCHER}$\r$\n" 0 loop
MessageBox MB_OK "$${IP_AND_DISPATCHER} found"
FileClose $2 ;close file
Quit
done:
FileSeek $0 0 END
FileWrite $0 "$\r$\n" ; new line
FileWrite $0 "${IP_AND_DISPATCHER}" ;write ip and dispatcher
FileWrite $0 "$\r$\n" ; extra line
FileClose $0 ;close file
Now its working, but is there a way to not write the 30.0.0.0 dispatcher so not the entire line... just, for example, the dispatcher word?
The NSIS wiki contains several examples for text files manipulations, with
2 examples for searching in a file with or without comments defining function for delegating the tedious string manipulations based on StrCmp
and another example for writing in a file, while there is another for replacing text
You can base your own work on these examples.

Resources