Why does the runas command require its command line to be quoted?

Commenter teo complained that the runas command requires its command line to be quoted.

Well, if you think about it, why single out runas? Pretty much all programs require their command line to be quoted if they contain special characters (like spaces that you want to be interpreted as part of a file name instead of as an argument separator). The runas command is just doing things the way everybody else does.

Recall that on Windows, programs perform their own command line parsing. This isn't unix where the command shell does the work of parsing quotation marks and globs before handing the (now-partly-parsed) command line to the child process. Mind you, most programs do not do their own custom parsing; they rely on the C runtime library to do the parsing into arguments.

Okay, but let's single out the runas command anyway, because runas does live in a slightly different world. It is a convention dating back to MS-DOS that programs which accept a command line as an argument do so without requiring quoting. The archetypal example of this is the command processor itself. Whatever you pass after the /C flag is treated as the command line to execute. Once the /C is encountered, parsing stops and everything from there to the end of the raw command line is treated as the argument. (It also imposes the requirement that /C be the last parameter on the command line.) (Note also that there is a special weirdo rule in the cmd.exe parser with respect to the /C and /K switches; see cmd /? for details.)

(Therefore, if you want a program that forwards its command line to another program, the way to do this is not to parse your command line and then try to unparse it but rather to just forward the original command line.)

The authors of the runas program appeared not to be aware of this historical convention at the time they wrote it. They just used the regular C runtime library command line parser, unaware that "programs which accept a command line on the command line" fall into a special alternate reality. Hence the need for the double-extra-quoting.

Back when the runas program was being developed, I pointed out this historical alternate reality to the people responsible for the runas program. They took my remarks under advisement but evidently chose to stick with the "standard" parsing rules rather than entering the little-known alternate reality. (As a consolation prize, they did add some examples at the end of the runas /? output to explain how quotation marks should be used.)

Comments (18)
  1. mastmaker says:

    Must be monday morning blues. I read the command aloud as 'roonaas' (instead of 'run as') and wondered why I had never heard of such a strangely named command line tool.

  2. 640k says:

    Trial & error with combinations of several ^ and " will usually solve any parsing. No need to remember anything, or try to use your brain, you'll have to test it when you need it because some programs are gui programs which gets the whole command line, and other use a c run time parser, which has different parsing rules in different compilers. An util which prints it's args is very handy in these circumstances.

    Example: A scheduled task which calls a batfile which calls runas which calls a program which should receive a " as a parameter. Good luck solving it without trial & error.

  3. Bob says:

    @640k:  Problem is that if we rely on experimentation instead of documentation, we never know whether we are doing things "correctly" (as Microsoft intended) or whether we are taking advantage of some undocumented or inadvertent behavior. If the latter, then our work may cause some future version of Windows to do unnatural things (compatibility shims or other gunk) to avoid breaking our programs.

    Of course, if everyone read the documentation, then this entertaining blog would have no reason to exist.

  4. Joshua says:

    So that's what it is. I couldn't figure out why it was misbehaving and finally had runas spawn a batch file from a path containing no spaces.

  5. Marty says:

    Ah, so you did have a time machine in this case… and it didn't change a thing. Well, so much for that plan.

  6. Danny says:

    He he here is the short… we see many years ago a young Ray talking to young developers (or maybe interns at the time) pointing out this alternative way and they shrug their shoulders with Ray saying a last warning "the future will point to me that I am right and you're wrong"…<current time>..Ray, the GOD, with his crowd at his feet, yelling at some now fat, older looking guys : "I told you I was right, didn't I?!!"

    The end (or Hollywood would do 2 sequels and then a prequel)

    [That's one way of looking at it. Or you could read it as "runas is a new program and therefore should be applauded for ridding itself of the arcane, backward-compatible, insane command line parsing rules of the past." -Raymond]
  7. Timothy Byrd says:

    By "ridding itself of the arcane, backward-compatible, insane command line parsing rules of the past", what giant leap did it make for mankind? (As opposed to the small step of simpler development for the team, at the time?)

    [A command line parser that parses its arguments more uniformly (and is therefore easier to understand)? -Raymond]
  8. Duncan says:

    Timothy,  I think your sarcasm detectors may be on the blink…  :)

  9. Anonymous Coward says:

    I just looked up cmd /? and it tells us of the following quoting rules:

    If no /S is present, and there are exactly two "s, and there's no &<>()@^| between them, and there are spaces between them, and the text between the quotes is an executable, then "s are preserved. Otherwise, if the first character is a " then this " and the last " are removed.

    Now, this is a strange way of formulating things, since it's (to my mind) inside-out, so I'll try to rephrase it.

    If the command string starts with a " followed by an executable, followed by another " then these two " are removed, unless /S is present, or there are more "s, or there's &<>()@^| in the executable name, or there are no spaces in the executable name.

    So, assuming cv*.exe are executables echoing their command line, you'll get:

    cmd /c "cv with spaces" -> "cv with spaces"

    cmd /c "cv with spaces" xyzzy -> "cv with spaces" xyzzy

    cmd /s /c "cv with spaces" xyzzy -> cv with spaces xyzzy

    cmd /c "cv with spaces" "xyzzy" -> cv with spaces" "xyzzy – NOTE: cv.exe will be run

    cmd /c "cv(braces)" xyzzy -> cv (braces) xyzzy – NOTE: cv.exe will be run, and a space is inserted; behaves like cv(braces) xyzzy

    cmd /c ""cv(braces)"" xyzzy -> "cv(braces)" xyzzy

    cmd /c "cv" xyzzy -> cv xyzzy

    Now, the function of /S is obvious: it gives you an escape hatch from the other weird rules. You can say:

    cmd /s /c ""cv" "xyzzy""

    cmd /s /c ""cv with spaces" "xyzzy""

    cmd /s /c ""cv(braces)" "xyzzy""

    And always know that the right executable / command is run with the parameters as you supplied them.

    The more than 2 "s rule looks like an old escape hatch. I think it had pretty much the same function as /S but it won't work as consistently, since it requires "s to be present in either the executable or its arguments.

    cmd /s /c "cv with spaces" -> cv with spaces – which runs cv.exe.

    cmd /c "cv with spaces" -> "cv with spaces" – which is wrong if you intended the "s to be used as your escape hatch.

    The &<>()@^| rule made it possible to feed multiple commands to cmd. Compare what happens if you enter these two commands:

    cmd /k echo x&echo y

    cmd /k "echo x&echo y"

    From this, it follows that you can get the same behaviour as /S like this:

    cmd /c "cv with spaces&" -> cv with spaces – runs cv.exe.

    In case you're worried about the errorlevel: it is preserved correctly.

    The ‘no spaces’ rule looks like a compatibility thing. Perhaps old programs freak out if their command line starts with a " and it was desirable to still allow old programs to be run with a full quoted path. But it won't work if the path contains spaces (no short path is substituted) or if you're running multiple commands, since cmd doesn't distinguish between the two very different reasons for removing "s and does it only once.

    All this was a good reminder of why I got into the habit of writing in a real programming language even when doing tasks traditionally done with batch.

  10. Ben says:

    I admit my ignorance here, but how do you get access to the unparsed command line? I have searched to no avail.

  11. Ben says:

    Because I suck at searching. LPTSTR WINAPI GetCommandLine(void); I have a little helper app with stupid "unparsing" that I need to go and fix.

  12. Wow, didn't know cmd /? had such a huge output.

    "(As a consolation prize"

    Punnery at it's best. :)

    Console-ation … ha ha…. ferget it.

    "they did add some examples at the end of the runas /? output to explain how quotation marks should be used.)"

    They made an example of you–and i quote–by slashing your questions?

    Or is /? actually the Raymond Parameter? So, runas /? actually means "run as raymond". Which makes sense, because it gives comments and examples, and, who knows, might actually run the command in a couple years.

  13. simcmd says:

    I would like a simulate flag on runas. It should spawn a replica of the current system as a virtual guest and run the command in it. And compare *everyting* relevant in the guest system before and after the command ran, and show the difference.

    That whould be useful.

    [Perhaps useful, but I don't see how creating a virtual machine falls within the scope of runas. (You also have to define "relevant".) -Raymond]
  14. Anonymous Coward says:

    Until it suddenly inexplicably breaks. Then the docs will be laughing at you.

  15. 640k says:

    There's no docs for what happens when nesting commands with batch, schtasks and runas. Also, there's usually only one combination of special chars which works, if any docs say otherwise it doesn't work!

  16. Anonymous Coward says:

    There's no docs for &c. – Now that's just trolling. Not to mention lying.

  17. 640k says:

    The documentaion means nothing, getting things to work means everything.

    Some commands, like schtasks, are expecting combinations of ' and ". Only admins can install scheduled tasks, therefore you have to run schtasks with runas, which complicates syntax considerably, so you want the command contained in a batch file. If password contains characters like %, ', " and space (which "experts" claim increases security), the best thing you can do is *getting things to work*, then reading the docs and laugh at it.

  18. 640k says:

    What is the url to where the exact combination of batch, schtasks and runas are documented?

Comments are closed.