2

I have recently been struggling to make a set of instructions work as a one-liner. What I want to achieve is to run a special CMD instruction with elevated privileges, but starting from an unprivileged CMD. I have discovered that what I want to do is achievable by leveraging PowerShell as middleman, and I successfully created some one-liners that work, but I cannot wrap my head around a more complex scenario. This is the flow of programs I am planning to use:

CMD (unprivileged) -> PowerShell (unprivileged, triggering admin privileges) -> Either CMD or PowerShell (now with admin rights) -> execution of the desired instruction (that needs admin rights)

I must start from an unprivileged CMD. I planned to launch a PS session from there because I found a nice "trick" (i.e., using -Verb RunAs at the end of the command) that lets me switch to an admin CMD/PS session by just pressing "Yes" in the Windows UAC GUI.

This is the final command I must run in an admin CMD/PS session:

tbcon -run:"a2lmerger --optionsfile _gen\swb\module\asap2\opt\a2lmerger_internal.opt"

Furthermore, this command must also be executed from a specific folder. I can confirm that, by itself, this command works fine.

I have proceeded step-by-step, and I can assure that this next command works when launched from PS:

cmd \"/k cd C:\MY\PATH\WITHOUT\SPACES && tbcon -run:"a2lmerger --optionsfile _gen\swb\module\asap2\opt\a2lmerger_internal.opt"\"

Thus, I tried to implement the full solution, launching it from an unprivileged CMD:

powershell.exe -Command Start-Process cmd \"/k cd C:\MY\PATH\WITHOUT\SPACES && tbcon -run:"a2lmerger --optionsfile _gen\swb\module\asap2\opt\a2lmerger_internal.opt" && exit\" -Verb RunAs

But this fails, as tbcon does not receive the argument correctly, and indeed reports me that:

[tbcon] ERROR - Invalid argument: '--optionsfile'.

I suspect this is because CMD messes up with the space between a2lmerger and --opstionsfile (and eventually the one between --optionsfile and _gen[...]), but I spent a lot of time trying to fix this without luck.

Additionaly, it would also be nice to be able to substitute C:\MY\PATH\WITHOUT\SPACES with a path that also features spaces, but that would be a bonus.

Thank you all for your help!

Jetboy
  • 129
  • 8

1 Answers1

2

Any " chars. that you need to preserve as part of command you pass to the Windows PowerShell CLI's -Command parameter must be escaped as \" (otherwise, the initial command-line parsing will remove them).

  • While you're already doing that for the nested cmd command line overall, the embedded " chars surrounding the -run: option value lack that kind of escaping.

  • Escaping them as \" isn't enough however, given that they need to be interpreted as " inside a PowerShell string literal, where " must be escaped as `". You must therefore combine these escaping mechanisms, in the right order, namely: `\"

    • The same applies to enclosing the cd argument in "..."

Therefore:

powershell.exe -Command Start-Process cmd \"/k cd `\"C:\MY\PATH\WITH SOME\SPACES`\" && tbcon -run:`\"a2lmerger --optionsfile _gen\swb\module\asap2\opt\a2lmerger_internal.opt`\" && exit\" -Verb RunAs

Caveat re edge cases:

cmd.exe itself has no concept of escaped " chars.; that is, even the " in \" is considered to start or end a double-quoted string, an nesting \"...\" therefore creates substrings that cmd.exe considers unquoted, causing characters such as & to be interpreted as cmd.exe metacharacters, up front, which can break the command.
This pitfall applies to any command run from cmd.exe, not just when calling PowerShell; here's a cmd.exe-only example:

:: From cmd.exe.
:: BREAKS, because the 2nd & is considered UNQUOTED causing
:: interpretation as the statement-sequencing operator.
:: Prints "A & \"B, then looks for a command named C\" D"
echo "A & \"B & C\" D"

Workarounds:

  • Manual, situational workaround: Selectively ^-escape such characters, but that requires specific awareness of which substrings cmd.exe considers unquoted, which is cumbersome and nontrivial.

    :: From cmd.exe.
    :: OK, due to ^-escaping of the 2nd &
    :: Prints "A & \"B & C\" D"
    echo "A & \"B ^& C\" D"
    
  • Methodical workarounds:

    • If supported by the target CLI, use "" in lieu of \" as an escaped " inside "..." strings, which fundamentally avoids the problem (cmd.exe, which doesn't recognize "" as special either, then in effect sees a concatenation of "..." strings, and therefore everything in them as quoted).
      CLIs created with Microsoft's compilers typically do accept "" (interchangeably with \"), which includes pwsh.exe, the PowerShell (Core) 7+ CLI, but - unfortunately - not powershell.exe, the Windows PowerShell CLI (see next point).
      When calling pwsh.exe, enclose a -Command argument in "..." overall, and use "" for embedded ":

      :: From cmd.exe.
      :: OK, due to "..." enclosure and
      :: escaping of embedded " as "" (if you tried to use \", this would break)
      :: Prints "A & B"
      pwsh.exe -Command " Write-Output ""A & B"" "
      
    • For powershell.exe, the Windows PowerShell CLI, the workaround is more cumbersome, unfortunately; use "^"" (sic) inside a -Command argument enclosed in "..." overall:

      :: From cmd.exe.
      :: OK, due to overall "..." enclosure and
      :: escaping of embedded " as "^"" (sic)
      :: Prints "A & B"
      powershell.exe -Command " Write-Output "^""A & B"^"" "
      
      • Unfortunately, this technique doesn't work inside for /f loops, necessitating more complex workarounds, discussed in the bottom section of this answer.
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    This is just awesome, much more than I expected. Thank you very much! – Jetboy Jun 16 '23 at 14:14
  • 2
    I'm glad to hear it; my pleasure, @Jetboy. It's tricky business, and having conceptual clarity helps. There are many answers that cover various aspects of the problem, so I thought I'd try a comprehensive overview. – mklement0 Jun 16 '23 at 14:19
  • 1
    I think you made an excellent job; it's not the first time I am asking something online, and while I am always trying to put the effort to first solve the problem by myself and then to at least detail precisely my issue to the web, I rarely get such a positive feedback with the answers I receive. – Jetboy Jun 16 '23 at 14:39