2

I'm using Start-Process to start another instance of Powershell as an administrator but when I try to pass the argument list, whether as a variable or as a plain string, Powershell removes the quotes. Below is the command I'm using:

$argu = '-noexit "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat"';
powershell Start-Process -Verb RunAs -FilePath powershell -ArgumentList $argu

This is the error I get:

x86 : The term 'x86' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included,
verify that the path is correct and try again.
At line:1 char:88
+ ... Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\v ...
+                    ~~~
    + CategoryInfo          : ObjectNotFound: (x86:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Thank you in advance for any help.

Update:

$argu = '''-noexit ""C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat""''';
powershell Start-Process -Verb RunAs -FilePath powershell -ArgumentList $argu

This almost fixes it but now I'm getting the error above in the second window instead of the first.

dkneeland
  • 80
  • 7

1 Answers1

3

(A) From inside PowerShell:

$argu = '-noexit -command & \"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat\"'
Start-Process -Verb RunAs -FilePath powershell -ArgumentList $argu

Note: I'm not calling Start-Process via powershell.exe, as there is generally no need for that.

  • The embedded " are \-escaped, which is what PowerShell requires when you call its CLI (perhaps surprisingly, given that PowerShell-internally it is ` that acts as the escape character).

    • That said given that the " are embedded inside '...' here, they shouldn't require extra escaping - see below.
  • The file path to execute is prefixed with call operator &, because you need it in order to execute files that are specified in quoted form.

  • Note that I've added -Command, which is not strictly necessary in Windows PowerShell, but would be if you ran your command from PowerShell Core (which now defaults to -File).


Alternatively, you could also specify your arguments individually, as part of an array, which is arguably the cleaner solution:

$argu = '-noexit', '-command', '&', 'de', 
  '\"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat\"'
Start-Process -Verb RunAs -FilePath powershell -ArgumentList $argu

Sadly, even in this case you need the extra, embedded quoting for arguments that contain spaces, which is a known Start-Process problem being tracked on GitHub.

PowerShell's handling of quoting when calling external programs is generally problematic; the current issues are summarized in this GitHub issue.


(B) From outside PowerShell (cmd.exe, a custom File Explorer context menu):

powershell -command Start-Process -Verb RunAs -FilePath powershell -ArgumentList '-noexit -command . ''C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat'''
  • single-quoting is now employed (with nested single quotes escaped as ''), because double-quoting would substantially complicate the escaping.

  • . is used instead of & to execute the .bat file, which avoids a problem with how the & is parsed; while . generally serves a different purpose than &, the two operators behave the same when calling external programs.

  • If you also want to set the working directory for the PowerShell session that ultimately opens elevated, you need to incorporate an explicit Set-Location (cd) call into the command string, because Start-Process -Verb RunAs always defaults to the SYSTEM32 folder (even the -WorkingDirectory parameter doesn't help in that case).

    • For that to work safely, however, you must quote the directory path using double-quoting, given that file names may contain single quotes; with %V as the directory path (which File Explorer supplies to commands invoked via custom context menus), the properly escaped Set-Location call looks like this (I wish I were kidding):

      • Set-Location \"\"\"%V%\"\"\"

Integrated into the full command (using Set-Location's built-in alias cd for brevity):

powershell -command Start-Process -Verb RunAs -FilePath powershell -ArgumentList '-noexit -command cd \"\"\"%V%\"\"\"; . ''C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat'''

As an aside: PowerShell Core now has a -WorkingDirectory (-wd) CLI parameter that allows you to control the startup directory more robustly (pwsh -wd "c:\path\to\dir" ...); in fact, it was precisely the File Explorer custom context-menu use case that prompted the introduction of this parameter.

mklement0
  • 382,024
  • 64
  • 607
  • 775