When I use Windows Run tool to call my exe with argument it work fine
I did below
cmd.exe /C "C:\ex\abc.exe" skk
Then my exe get a hit and i got skk as an argument. BUt I i did
cmd.exe /C "C:\ex\abc.exe" "sk k" then my exe does not call. Why?
But the same thing work fine in cmd line
"C:\ex\abc.exe" "sk k"
This is by design
If more than two quote characters are present after the /C switch, then "behavior is to see if the first character is a quote character and if so, strip the leading character and remove the last quote character on the command line, preserving any text after the last quote character.", unless the following conditions are met:
no /S switch
exactly two quote characters
no special characters between the two quote characters, where special is one of: &<>()#^|
there are one or more whitespace characters between the two quote characters
the string between the two quote characters is the name of an executable file.
So, when you do
cmd.exe /C "C:\ex\abc.exe" "sk k"
it's trying to execute
C:\ex\abc.exe" "sk k
which, obviously, doesn't work. If you want to run your exe with an argument containing the whitespace, try
cmd.exe /C C:\ex\abc.exe "sk k"
Or wrap the the whole command in double quotes like so:
cmd.exe /C ""C:\New Folder\abc.exe" "sk k""
Related
How do you pass quoted arguments to an executable in a single-quoted evaluation such as FOR /F "delims=" %%i IN ('"executable path" arg1 "arg2 which contains spaces"') do ...?
As per many of the answers here, I'm trying to use the output of a console app in a Windows batch script, using the single quotes to get the console to evaluate it.
However, I need to quote some of the arguments I want to pass to that executable, which also needs to be quoted, as the path contains spaces as well.
But when I do that, the quoting around the executable path breaks.
Here is the would-be line:
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^="!album!"') DO set "falbum=%%i"
(Both !PathToExe! and !album! contain spaces. It seems like I need to escape the equal signs here, hence the circumflexes. Delayed expansion is on)
The above results in "Outcome A": Quoting is broken for the exe path
'<Part of path to exe>' is not recognized as an internal or external command, operable program or batch file.
I've tried different combinations of different quote usages and escapings, but haven't found a way to make it work.
Here are some attempts and their results:
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^=!album!') DO set "falbum=%%i")
No quotes around !album! results in "Outcome B": As expected, only the first word gets passed along with string=, all the other words get scattered as individual arguments.
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^=^"!album!^"') DO set "falbum=%%i")
FOR /F "delims=" %%i IN ('^"!PathToExe!^" action^=sanitize string^=^"!album!^"') DO set "falbum=%%i")
Trying to escape the quotes for the string= argument or both exe path and string arg: Outcome A (still breaks the quoting for the exe path, gives:)
'<Part of path to exe>' is not recognized as an internal or external command, operable program or batch file.
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^=^'!album!^'') DO set "falbum=%%i")
Using escaped single quotes: Outcome B again
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^='"!album!") DO set "falbum=%%i")
Ending the single quote before the string= value and simply having it in quotes after that seems to result in everything being taken as a single first argument (command/path):
The system cannot find the file '"<path to exe>" action=sanitize string='"<Album var with spaces and whatnot>".
It does not matter whether the quotes are part of the variables or literally typed in the IN ('...') line.
Simple testing:
You could test this behavior if you copied %SystemRoot%\System32\cmd.exe to a directory with spaces, e.g. C:\folder with spaces\ and pasted the following script there:
#echo off
setlocal EnableDelayedExpansion
set PathToExe="%~dp0cmd.exe"
REM Toggle the next line to compare between quoted path with spaces and path without quotes or spaces:
REM set PathToExe=cmd.exe
set string=%~dp0
FOR /F "delims=" %%i IN ('!PathToExe! /C CD C:\windows\system32 ^& dir !string!') DO set "fstring=%%i"
echo !fstring!
pause
This should illustrate the challenge of having two quoted sections in one statement.
If the !string! variable remains unquoted, you'll get "The system cannot find the file specified.".
If the quotes of the !PathToExe! variable break, you'll see something like "'C:\folder' is not recognized as an internal or external command, operable program or batch file.".
The for /F command, when used to capture and parse command output, actually uses cmd /C to execute that command, which handles quotation marks in a particular way. From its help (cmd /?):
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
This means that:
for /F "delims=" %%I in ('"executable path" arg1 "arg2 which contains spaces"') do (…)
actually tries to execute the command line:
cmd /C "executable path" arg1 "arg2 which contains spaces"
leading to:
executable path" arg1 "arg2 which contains spaces
which is obviously invalid syntax.
To overcome this issue provide an additional pair of quotes:
for /F "delims=" %%I in ('^""executable path" arg1 "arg2 which contains spaces"^"') do (…)
It is a good idea to escape these additional quotes (by ^"), so there is no need to alter any potential escape sequences.
I'm trying to escape some calls in bat file and I found out that I don't understand even on simple example the weird handling of double quotes:
Try
cmd /c "echo " "%TEMP%" rem this gives: " "C:\Users\xyz\AppData\Local\Temp
cmd /c "echo" "%TEMP%" rem this gives: The filename, directory name, or volume label syntax is incorrect.
cmd /c "echo beg "TEMP" %TEMP%" rem this gives: beg "TEMP" C:\Users\xyz\AppData\Local\Temp
cmd /c "echo beg ^"TEMP^" %TEMP%" rem this gives: beg "TEMP" C:\Users\xyz\AppData\Local\Temp
cmd /c "echo beg \"TEMP\" %TEMP%" rem this gives: beg \"TEMP\" C:\Users\xyz\AppData\Local\Temp
Just open command prompt (cmd.exe) and paste code.
The results are the same when copy/paste to cmd.exe or running a bat file.
What I would expect is that cmd /c "echo beg \"TEMP\" %TEMP%" should work correcctly. At least according to http://daviddeley.com/autohotkey/parameters/parameters.htm#WIN .
But I don't understand output from all the samples. Anybody could explain me that behaviour?
Edit:
The site I'm referencing just explains how arguments are parsed on Windows. E.g. http://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES
What is my expected output?
I just want to know how that passing of double quotes work.
Later I'd like to construct command lines like this one:
pwsh -noprofile -command "produceSomeStringsToFind | % { rg -g testfile* \" $_ some string that ends with quote\\\"" . }"
where rg is https://github.com/BurntSushi/ripgrep - where the \" $_ some string that ends with quote\\\"" part is regular expression where I need to escape the quotes.
From the help text of cmd /?:
[...]
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
[...]
It becomes clear that you are facing the situation explained in section 2., because echo is not an executable file but an internal command. So if the first character is a ", it becomes removed and so becomes the last ", and all the other characters are preserved.
Now let us go through your command lines. So after being parsed and processed by cmd /c:
cmd /c "echo " "%TEMP%" becomes echo " "C:\Users\xyz\AppData\Local\Temp.
cmd /c "echo" "%TEMP%" becomes echo" "C:\Users\xyz\AppData\Local\Temp; then the command echo" is tried to be executed, but which is not a valid one, hence it fails.
cmd /c "echo beg "TEMP" %TEMP%" becomes echo beg "TEMP" C:\Users\xyz\AppData\Local\Temp.
cmd /c "echo beg ^"TEMP^" %TEMP%" becomes echo beg "TEMP" C:\Users\xyz\AppData\Local\Temp, because escaping with ^ happens even before cmd /c is executed, so it receives the already escaped literal " characters.
cmd /c "echo beg \"TEMP\" %TEMP%" becomes echo beg \"TEMP\" C:\Users\xyz\AppData\Local\Temp, because the \ is nothing special to cmd.
If you want to output the text "%TEMP%" (including the quotes), you could do this:
rem // This preserves all quotes, because the first character is not such:
cmd /c echo "%TEMP%"
rem // This removes the outer-most pair of quotes, because the first character is such:
cmd /c "echo "%TEMP%""
rem /* This removes the outer-most pair of quotes too, since `cmd /c` receives the already
rem escaped `"`; however, this could be useful to hide these quotes from the hosting
rem `cmd` instance, which avoids issues when `%TEMP%` contains special characters
rem (like `&` or `^`), which you would otherwise have to individually escape: */
cmd /c ^"echo "%TEMP%"^"
Edit 3 (SOLUTION):
As michael_heath described in his answer, the issue came down to two things: how exactly windows builds commands when executing something through a shortcut, and the very specific (and frankly ridiculous) consequences of the \C switch on cmd.exe. For future reference, if any other poor soul stumbles into this StackOverflow question, the problem was fixed by changing the "Target" property in the shortcut to a slightly edited version of Michael's answer, specifically C:\Windows\System32\cmd.exe /C #"C:\{path-to-script}\link.bat". Here's a screenshot too, if necessary, although you unfortunately can't see the whole Target line.
Huge thanks again to Michael.
I am attempting to make a personal batch utility to create a symlink on the desktop, much in the same way "Send to... > Desktop" works with shortcuts. I use symbolic links frequently to allow things like my bash configuration files (.bashrc and .bash_profile, etc) to be version controlled elsewhere for portability, and for several other things on my computer.
For ease of use, my idea was to create a simple batch file to do this for me, and place the symlink on the desktop. Then, I would put a shortcut to this file in the Send To folder so it appears in Send To in the context menu (I am aware that mklink requires admin privileges, so the shortcut is set to run as administrator also).
The following is the file I have written:
#echo off
set f=%~1
set switch=
if exist "%f%\*" set switch=/D
for /F "delims=" %%i in ("%f%") do set name=%%~nxi
mklink %switch% "%USERPROFILE%\Desktop\%name%" "%f%"
if not %ERRORLEVEL%==0 pause
Here is the general idea of what I'm trying to do:
Strip the quotes on the input, if any (%~1)
Check if the input is a directory
Get the base name and file extension of the input (%%~nxi)
Make the link
If an error occurred, pause so it can be seen rather than exiting (because the batch file is called from the shortcut)
It works perfectly fine until I give it an input that contains spaces in the name of the file or directory. I actually haven't tested what happens if there is a directory with a space in the path, but not in the base name of the actual file or directory, but I assume the same problem will be present.
I have made several changes to attempt to get it to work with files with spaces, including stripping the quotes on the input in that first line so that the quotes aren't doubled later, and that "delims=" thing on the for loop. Those two solutions I found here, actually.
But despite my best efforts, no matter what I do, the file closes immediately when given an input with a space. I have littered every line with pauses, run the script from the command line with a manually entered input so it would not exit, and run each individual command (where possible) from the command line.
Infuriatingly, when I run it from the command line or run the individual commands, it all works perfectly even with spaces in the input. I even created another batch file that does nothing but output the input it receives and ran that from Send To, and confirmed that the input is the same as I entered from the command line.
What on Earth is going wrong then when called from that shortcut in Send To?
Edit 1: The properties of the shortcut itself are as follows:
Target: C:\Users{username}\vc\git\util-scripts\bat\link.bat
Start in: C:\Users{username}\vc\git\util-scripts\bat
Here is a screenshot as well:
Because I just made my account here I can't embed the picture but here it is
Edit 2: This is the current code I am using, as suggested by Gerhard Barnard, however the problem still persists:
#echo off
set "fname=%~1"
set switch=
if exist "%fname%\.*" set "switch=/D"
for /F "delims=" %%i in ("%fname%") do (
mklink %switch% "%USERPROFILE%\Desktop\%%~nxi" "%fname%"
if errorlevel 1 pause
)
#echo off
setlocal
rem Set the path for the created symlink.
set "linkdir=%USERPROFILE%\Desktop"
for %%A in (%*) do call :link "%%~A"
rem Check results.
echo: & dir /A:L "%linkdir%" & pause
exit /b
:link
set "switch="
if exist "%~1\*" set "switch=/D"
for /F "delims=" %%A in ("%~1") do set "name=%%~nxA"
if not defined name echo Variable "name" not defined.& exit /b 1
mklink %switch% "%linkdir%\%name%" "%~1"
exit /b 0
Your batch-file code is working.
This code does multiple file or folders.
This code also helped to test all at once,
files, folders, symlinked files and symlinked
folders as targets.
If you only want 1 target to be processed,
then just change the %* to "%~1".
The main issue is the command string in the shortcut.
C:\Users\{username}\vc\git\util-scripts\bat\link.bat
The file type of .bat is going to build a command such as:
C:\Windows\System32\cmd.exe /C "C:\Users\{username}\vc\git\util-scripts\bat\link.bat" %*
%* is substituted with the passed arguments.
If you have the command with an argument with double quotes,
it may look like:
C:\Windows\System32\cmd.exe /C "C:\Users\{username}\vc\git\util-scripts\bat\link.bat" "C:\Users\a file.txt"
The command string after /C has 4 double quotes
and double quotes are at both ends.
The behavior changes due to the double quotes.
A quote from cmd /?:
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
In section 1, "no /S switch" is true, then the next is
"exactly two quote characters" which is false.
This now applies section 2, which can make the
command string after /C with stripped double quotes:
C:\Users\{username}\vc\git\util-scripts\bat\link.bat" "C:\Users\a file.txt
The space is quoted though the rest is exposed,
which is an invalid command string in this case.
Note that C:\Users\a file.txt is an example
passed argument that was double quoted as
"C:\Users\a file.txt".
A change in the command string in the shortcut to:
C:\Windows\System32\cmd.exe /C echo: & "C:\Users\{username}\vc\git\util-scripts\bat\link.cmd"
The command is now C:\Windows\System32\cmd.exe which
gives some more control with the command string.
After the /C, echo: is used to avoid the command
string beginning with a double quote, which helps to
prevent double quotes being stripped at both ends because
the command string no longer starts with a double quote.
After the & is the command that is important and will
now work even if the arguments end with a double quote.
You can replace the echo: & with another initial command.
You can also use # before the command string, so the shortcut
command string would be:
C:\Windows\System32\cmd.exe /C #"C:\Users\{username}\vc\git\util-scripts\bat\link.cmd"
So whatever works the best for your use case.
Try without the /F option which is not needed here, we also do not need to set a variable as it will work perfectly fine with the expanded meta variable:
#echo off
set "fname=%~1"
set switch=
if exist "%fname%\.*" set "switch=/D"
for %%i in ("%fname%") do (
echo mklink %switch% "%USERPROFILE%\Desktop\%%~nxi" "%fname%"
if errorlevel 1 pause
)
Findstr is supposed to support regular expressions and the way I am using it I need to have an OR to check if a file ends in .exe OR .dll. However I cannot get the OR operation to work. Windows thinks on using | that I try to pipe the previous command and OR is read as literal OR.
findstr.exe in Windows system32 directory supports only a very limited set of regular expression characters. Running in a command prompt window findstr /? results in getting displayed help for this console application listing also the supported regular expression characters with their meanings.
But as Eryk Sun explained in his comment above, multiple search strings can be specified on command line to build a simple OR expression.
In case of having a list file FileNames.lst containing for example
C:\Program Files\Internet Explorer\ieproxy.dll
C:\Program Files\Internet Explorer\iexplore.exe
C:\Program Files\Internet Explorer\iexplore.exe.mui
and just all file names ending with .dll OR .exe case-insensitive should be output by command findstr, the command line for getting this output could be:
%SystemRoot%\system32\findstr.exe /I /R "\.exe$ \.dll$" FileNames.lst
The output is for the example lines in FileNames.lst:
C:\Program Files\Internet Explorer\ieproxy.dll
C:\Program Files\Internet Explorer\iexplore.exe
The space in regular expression search string is interpreted by findstr as a separator between the two strings. Therefore findstr searches with the regular expression strings \.dll$ and \.exe$ and returns all lines where one of the two expressions matches a string.
Another method to OR two or more regular expression strings would be using parameter /C:"..." multiple times on command line which is necessary when a regular expression search string contains one or more spaces which should be included as literal character(s) in search expression.
%SystemRoot%\system32\findstr.exe /I /R /C:"\.dll$" /C:"\.exe$" FileNames.lst
The result is the same as above with the other command line.
But for this specific task it is not necessary at all to run a regular expression search as findstr offers also the parameter /E for returning only lines where the searched strings are found at end of a line.
%SystemRoot%\system32\findstr.exe /E /I /C:.exe /C:.dll FileNames.lst
A brief description between the differences on using "..." or /C:"...":
"regexp1 regexp2 regexp3" means searching for a line with a string matched by one of the three space separated regular expressions. The option /R can be used additionally to explicitly interpret the three strings between the two spaces as regular expressions. It is advisable to do so for making it 100% clear for findstr and every reader that the search strings are interpreted as regular expressions.
/L "word1 word2 word3" means searching for a line with a string matched by one of the three space separated literally interpreted strings. The used option /L forces explicitly an interpretation of the three strings between the two spaces as literal strings and not as regular expressions.
/C:"word 1" /C:"word 2" /C:"word 3" means searching for a line with a string matched by one of the three literally interpreted strings on which the space character is interpreted as space. The option /L can be used additionally to explicitly interpret the three search strings between as literal strings. It is advisable to do so for making it 100% clear for findstr and every reader that the search strings are interpreted as literal strings.
/R /C:"reg exp 1" /C:"reg exp 2" /C:"reg exp 3" means searching for a line with a string matched by one of the three regular expressions strings on which the space character is interpreted as space. The option /R forces explicitly an interpretation of the three strings as regular expressions with space being interpreted as space.
I'm trying to do this:
cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out"
However, I have problems which are down to the way cmd.exe works. If you read the help for it, it handles " characters in a special way. See the help at the end of question. So, this doesn't execute correctly... I'm guessing cmd.exe strips some quotes which makes the statement ill-formed.
I can do this successfully:
// quotes not required around folder with no spaces
cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > C:\temp\FolderWithNoSpaces\SomeProgram.out
But, I really need the first one to work. Is there away around the strange quote processing that cmd.exe uses? I want it to preserve all of the quotes, but there doesn't appear to be an option to make it do that.
Help taken from output of: cmd /?
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
the two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
Ah. doh. Think I've answered my own question.
If you use /S, and wrap the whole thing in quotes, it just removes those outer quotes.
cmd.exe /S /C " do what you like here, quotes within the outermost quotes will be preserved "
I think you'll find that your example works absolutely fine as it is.
cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out"
I have reproduced your example here
http://pastebin.com/raw.php?i=YtwQXTGN
C:\>cmd /c "c:\Program Files\my folder\my long program.exe" > "c:\temp\spaces are here\a.a"
C:\>type "c:\temp\spaces are here\a.a"
my long program.exe has run
C:\>
further example demonstrating it works with "my long program.exe", removing cmd /c, it operates fine too.
C:\>"c:\Program Files\my folder\my long program.exe" > "c:\temp\spaces are here\
a.a"
C:\>type "c:\temp\spaces are here\a.a"
my long program.exe has run
C:\>
Another example, but with replace. replace with no parameters says "source path required" "no files replaced"
C:\>replace > a.a
Source path required
C:\>type a.a
No files replaced
Exactly the same effect when they're in folders with spaces.
C:\>cmd /c "c:\Program Files\my folder\replace.exe" > "c:\temp\spaces are here\r.r"
Source path required
C:\>type "c:\temp\spaces are here\r.r"
No files replaced
C:\>
further demonstration with replace
without cmd /c works fine too.
C:\>"c:\Program Files\my folder\replace.exe" > "c:\temp\spaces are here\r.r"
Source path required
C:\>type "c:\temp\spaces are here\r.r"
No files replaced
C:\>
The reason why your example works fine
cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out"
and how/why it works the way it does, is because the > is interpreted as special by the host.exe So this part cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" - I think - is evaluated first. i.e. cmd /c does not see the > and after.
cmd /? shows 2 cases
Case 1 and Case 2. Your example fits Case 1
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
You can test for sure that your example fits case 1, because if you add /s (without adding any more quotes or making any change at all to your example other than adding /s), then you get a different result, because it makes your example hit case 2. So that proves that your example is definitely a case 1. And it clearly meets all the criteria of case 1.
If your example were a case 2, and you added /s, then it'd make no difference.
Your answer is interesting because it shows an alternative way of getting your result, but in case 2. By adding additional outter quotes and adding /s.
But actually, when you add those additional outter quotes, then you've just made it a case 2, and adding a /s on top of that won't make a difference.
C:\>cmd /c "c:\Program Files\my folder\replace.exe"
Source path required
No files replaced
C:\>cmd /s /c "c:\Program Files\my folder\replace.exe"
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.
C:\>cmd /c ""c:\Program Files\my folder\replace.exe""
Source path required
No files replaced
C:\>cmd /s /c ""c:\Program Files\my folder\replace.exe""
Source path required
No files replaced
C:\>
The example in your question worked fine
cmd.exe /C "C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out"
Your alternative (with the /S and outer quotes) you give as an answer to make the example work, works fine too
cmd.exe /S /C ""C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out""
Though your answer which is an alternative, can actually be simplified by removing the /S because it's already a case 2, so adding /s won't make any difference. So this would improve the solution given in your answer
cmd.exe /C ""C:\Program Files\Somewhere\SomeProgram.exe" > "C:\temp\Folder Containing Spaces\SomeProgram.out""
Your example which you described as a problem in your question, and your solution, produce the same good result. But one big difference I suppose, (and I am not sure how to test for it), but one difference in the way your example works, and the way the solution in your answer works, is I think in the case of your example, the hosting/invoking cmd.exe does the redirect to the file. Whereas in your solution's example, the invoked cmd.exe is passed the > by the host cmd.exe, and so the invoked cmd.exe does the redirect. Also of course, your example is a case 1, while your solution is an amendment you made (very well) to make it work in case 2.
I hope I haven't erred here, I may have. But your question and answer did help me wrap my head around how cmd and in particular cmd /c is working!
Perhaps your example was an oversimplification of your actual one, and your actual one did fail and needed your amendment. If your example case, had been a tiny bit more complex, by for example, having a parameter to the program that took quotes, then it'd fail Case 1, and you would indeed need outter quotes (/S would not change the result, so no /S would be necessary, as it'd already be a case 2 once you add those needed outer quotes). But the example you gave in your question actually seems to me to work fine.
Added - A related Q and A What is `cmd /s` for?