Search code examples
cmdwhitespacensispathname

NSIS Runtime CMD with spaces in path and parameter


I have a Windows .bat script which needs to be run from a NSIS installer at runtime.

The script is invoked as follows:

   ; Debug Messages to check values set correctly
   MessageBox MB_OK "Script ${INSTDIR}\script\settingsLocation.bat"
   MessageBox MB_OK "INSTDIR $INSTDIR "
   MessageBox MB_OK "SettingsDirType $SettingsDirType"
   MessageBox MB_OK "SettingsDirName $SettingsDirName"
   MessageBox MB_OK "Calling script ${INSTDIR}\script\settingsLocation.bat $INSTDIR $SettingsDirType $SettingsDirName"

   nsExec::ExecToStack 'CMD.exe /C ""${INSTDIR}\script\settingsLocation.bat"" ""${INSTDIR}"" $SettingsDirType $SettingsDirName'

   ; Check result status and output
   Pop $0
   MessageBox mb_ok "CMDout 0=$0"
   Pop $0
   MessageBox mb_ok "CMD Out 1=$0"

Using the above, the variable $INSTDIR is not expanded, so not surprising the command fails to find the script.

$INSDIR is "C:\Program Files (x86)\Prog Name" (three spaces).

But I use the following (replace the "" with "):

nsExec::ExecToStack 'CMD.exe /C "${INSTDIR}\script\settingsLocation.bat" "${INSTDIR}" $SettingsDirType $SettingsDirName'

I get :

'C:\Program' is not recognized as an internal command, operable program or batch file.

Clearly I'm falling between the 2 stools of non expansion and full expanion ignoring quotes.

How can I preserve the quotes such that the command would run as if it were typed manually as follows:

"C:\Program Files (x86)\Prog Name\script\settingsLocation.bat" "C:\Program Files (x86)\Prog Name" DTYPE DNAME

Update 1 (following Anders's reply):

I tried the following mod:

   nsExec::ExecToStack 'CMD.exe /C "$INSTDIR\script\settingsLocation.bat" "$INSTDIR" $SettingsDirType $SettingsDirName'

i.e change ${INSTDIR} to $INSTDIR

This gives :

'C:\Program' is not recognized as a internal or external command

Update 2

Tried escaping the inner double quotes as follows:

   nsExec::ExecToStack 'CMD.exe /C \"$INSTDIR\script\settingsLocation.bat\" \"$INSTDIR\" $SettingsDirType $SettingsDirName'

But this gave:

'\"C:\Program Files\....\" is not a recognised as an internal; or external command,

Update 3 (Resolved!!)

Following further help from Anders below, adding the if 1==1 bit finally got it working:

   nsExec::ExecToStack 'CMD.exe /C if 1==1 "$INSTDIR\script\settingsLocation.bat" "$INSTDIR" $SettingsDirType $SettingsDirName'

Solution

  • Instdir is a variable, not a define, so you must use $InstDir, not ${InstDir}.

    CMD.exe has crazy quote handling and will sometimes remove your quotes but there is a little workaround for that:

    nsExec::ExecToStack 'CMD.exe /C if 1==1 "c:\path with spaces\app.exe" param1 "par am 2"'