我需要 .bat 文件中的通用命令以管理员身份启动指定的 powershell 脚本并绕过当前的 ExecutionPolicy。
关键是使用-ExecutionPolicy
CLI参数(只有下面的内部调用需要它; 外部powershell
调用的唯一目的是使用提升(以管理员身份)启动目标会话,它本身不涉及执行脚本文件):
- 警告:如果您的有效执行策略由GPO(组策略对象)控制,则它不能被覆盖[1] - 无论是使用
-ExecutionPolicy
CLI 参数还是在会话中Set-ExecutionPolicy
- 下面的解决方案都不起作用。有关详细信息,请参阅此答案。
此外 - 与执行策略无关 -需要额外的工作来保留调用者的工作目录,因为提升的会话默认为 SYSTEM32 目录。因此,下面的命令包含一个显式Set-Location
调用来设置工作目录。请注意,为了调用位于该目录中的脚本,您需要为其名称添加前缀.\
(例如,.\script.ps1
而不是仅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
.ps1
在指定脚本终止后保持提升的会话打开;如果您希望会话及其窗口自动关闭,请将其删除。
-noprofile
禁止加载配置文件脚本;在第二次 powershell
调用中,这不是绝对必要的,但对于可预测的执行环境仍然是可取的。
笔记:
[1] 有一个有限的解决方法:执行策略仅与脚本文件有关,因此将脚本文件的内容读入内存并执行 - 无论是通过首先构建脚本块还是将其直接传递给通常避免Invoke-Expression
- 是一种绕过主动执行策略的方法。一个简化的例子:
powershell -noprofile -c "Invoke-Expression (Get-Content -Raw c:\path\to\foo.ps1)"
. 也就是说,如果以这种方式执行的代码调用其他脚本文件,则该技术将不起作用,这也可能 在自动导入模块时隐式发生。