I need a generic command in a .bat file to launch a specified powershell script as Admin AND bypassing the current ExecutionPolicy.
The key is to use the -ExecutionPolicy
CLI parameter (which only the inner powershell
call below needs; the sole purpose of the outer one is to launch the target session with elevation (as admin), which itself doesn't involve execution of a script file):
- Caveat: If your effective execution policy is controlled by GPOs (Group Policy Objects), it can not be overridden[1] - neither with the
-ExecutionPolicy
CLI parameter, nor in-session with Set-ExecutionPolicy
- the solution below won't work. See this answer for details.
Also - unrelated to execution policies - additional work is required in order to preserve the caller's working directory, because elevated sessions default to the SYSTEM32 directory. Therefore, the command below incorporates an explicit Set-Location
call to set the working directory. Note that in order to call a script located in that directory you need to prefix its name with .\
(e.g., .\script.ps1
instead of just script.ps1
):
:: Run from cmd.exe / a batch file.
:: The target script file is '.\script.ps1' in this example, and
:: 'foo 1' and 'bar' are sample arguments to pass to it.
powershell -noprofile -c Start-Process -Verb RunAs powershell '-noexit -noprofile -ExecutionPolicy Bypass -c Set-Location -LiteralPath ''%CD:'=''''%''; ^& .\script.ps1 ''foo 1'' bar'
-noexit
keeps the elevated session open after the specified .ps1
script terminates; remove it, if you want the session and thereby its window to close automatically.
-noprofile
suppresses loading of the profile scripts; in the second powershell
call, that isn't strictly necessary, but still advisable for a predictable execution environment.
Note:
In order to avoid "
-related escaping hell, the above solution uses '...'
strings only, as understood by PowerShell in the context of a -c
(-Command
) CLI call, which, however, assumes the following:
The script file name / path itself and the pass-through arguments mustn't contain '
chars. - if they do, they must be enclosed in ''....''
and the embedded '
must be escaped as ''''
(sic).
- For the
Set-Location
call above, this is handled automatically by using cmd.exe
's string-replacement technique on its %CD%
variable (%CD:'=''''%
).
If the script file path or pass-through arguments contain spaces, there mustn't be runs of multiple spaces - if so (which would be very unusual in the case of paths), "
-quoting would have to be used. Otherwise, values with spaces must be enclosed in ''...''
, as shown with the foo 1
argument above.
Since the script file is invoked via -c
(-Command
) rather than via -f
(-File
), the interpretation of arguments passed to it may situationally differ - see this answer.
[1] There is a limited workaround: Execution policies only relate to script files, so reading a script file's content into memory and executing that - be it via constructing a script block first or by passing it directly to the usually-to-be-avoided Invoke-Expression
- is a way to bypass the active execution policy. A simplified example:
powershell -noprofile -c "Invoke-Expression (Get-Content -Raw c:\path\to\foo.ps1)"
. That said, the technique won't work if the code executed this way calls other script files, which may also happen implicitly when modules are auto-imported.