I have a PowerShell setup which I want to execute on a computer where perhaps the execution policy is restricted and requires admin rights.
Ideally, I could wrap it in a cmd batch like follows:
powershell -Command "Start-Process powershell -Verb runAs -ArgumentList '-noexit','-ExecutionPolicy','bypass','-File','C:\path\setup.ps1'"
The problem is that I can't make it to work when C:\path\setup.ps1
contains spaces, and also the path does not work if relative (with cd C:\path
).
Any help?
In Windows PowerShell (see bottom section for PowerShell (Core) 7+), using Start-Process -Verb RunAs
to launch a command with elevation (as admin), invariably uses C:\Windows\SYSTEM32
as the working directory - even a -WorkingDirectory
argument, if present, is quietly ignored.
Thus, in order to set a custom working directory and to invoke a script there, the -Command
CLI parameter must be used, and a Set-Location
(cd
) call must precede a call to a script specified by relative path.
While passing the pass-through arguments individually to the Start-Process
cmdlet's -ArgumentList
parameter may be conceptually preferable, a long-standing bug unfortunately makes it better to encode all arguments in a single string - see this answer.
Doing all this from cmd.exe
, via powershell.exe
, the Windows PowerShell CLI, complicates matters due to escaping requirements.
Applied to your powershell.exe
CLI call,
assuming working dir. C:\path 1
and script file setup 1.ps1
:
powershell -Command "Start-Process -Verb RunAs powershell '-NoExit -ExecutionPolicy Bypass -Command cd \\\"C:\path 1\\\"; & \\\".\setup 1.ps1\\\"' "
Note how the embedded "
chars. are doubly escaped, as \\\"
: first as \"
in order to be preserved during the outer powershell.exe
call, and then again for the inner one.
While this typically works, there are edge cases where \
-based escaping is not enough, namely if the script path or file name contains a cmd.exe
metacharacter, such as &
; in that case, "^""
(sic) must be used for the first round of "
-escaping:
powershell -Command "Start-Process -Verb RunAs powershell '-NoExit -ExecutionPolicy Bypass -Command "^"" cd \\"^""C:\path 1\\"^""; & \\"^"".\setup 1.ps1\\"^"" "^""'"
Note:
From cmd.exe
(batch files), "^""
(sic) is the most robust way to pass "
that are embedded in an overall "..."
string to powershell.exe
, as shown above, whereas it is ""
for pwsh.exe
, the PowerShell (Core) CLI (see below).
By contrast, from a shell-free context (e.g., a scheduled task) \"
works robustly, in both editions.
See this answer for details.
When you call pwsh.exe
instead - the PowerShell (Core) 7+ CLI - simplifications are possible and a workaround may not even be needed:
pwsh.exe
does preserve the caller's working directory by default even with -Verb RunAs
and does respect a -WorkingDirectory
argument with -Verb RunAs
.
In addition to \"
, pwsh.exe
more simply supports ""
for embedding "
chars. in "..."
strings; the latter works robustly from cmd.exe
pwsh.exe
itself now has a -WorkingDirectory
parameter, which therefore allows invoking the script with the -File
parameter:
pwsh.exe -WorkingDirectory "C:\path 1" -Command "Start-Process -Verb RunAs pwsh.exe '-NoExit -ExecutionPolicy Bypass -File ""C:\path 1\setup 1.ps1""'"