1

我正在尝试编写一个 Powershell 脚本来自动执行新计算机上的一般任务,包括安装软件。在阻止我运行我一直在编写的自动化脚本时,ExecutionPolicy 一直是我存在的祸根。

我的一个 PS 脚本需要提升的管理员权限,所以我有一个批处理文件,我在其中调用以管理员身份启动 PS,但由于 ExecutionPolicy,我仍然遇到脚本立即关闭/失败的问题。理想情况下,我想要一种基于每个脚本绕过 ExecutionPolicy 的方法,而不是完全更改它然后再将其更改回来。

我查找了不同的 Set-ExecutionPolicy 方法,但它们似乎不起作用。

我需要 .bat 文件中的通用命令以管理员身份启动指定的 powershell 脚本并绕过当前的 ExecutionPolicy。

4

1 回答 1

2

我需要 .bat 文件中的通用命令以管理员身份启动指定的 powershell 脚本并绕过当前的 ExecutionPolicy。

关键是使用-ExecutionPolicy CLI参数(只有下面的内部调用需要它; 外部powershell调用的唯一目的是使用提升(以管理员身份)启动目标会话,它本身不涉及执行脚本文件):

  • 警告:如果您的有效执行策略由GPO(组策略对象)控制,则它不能被覆盖[1] - 无论是使用-ExecutionPolicyCLI 参数还是在会话中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调用中,这不是绝对必要的,但对于可预测的执行环境仍然是可取的。

笔记:

  • 为了避免"-related escaping hell,上述解决方案'...'仅使用字符串,正如 PowerShell 在-c( -Command) CLI调用的上下文中所理解的那样,但是假设如下:

    • 脚本文件名/路径本身和传递参数不得包含'字符。- 如果这样做,则必须将它们包含在''....''其中,并且必须将嵌入 '的内容转义为''''(原文如此)。

      • 对于Set-Location上面的调用,这是通过对其变量 ( )使用字符串替换技术自动处理的。cmd.exe%CD%%CD:'=''''%
    • 如果脚本文件路径或传递参数包含空格,则不能运行多个空格 - 如果是这样(这在路径的情况下非常不寻常),"则必须使用 - 引用。否则,带有空格的值必须包含在 中''...'',如上面的foo 1参数所示。

    • 由于脚本文件是通过-c( -Command) 而不是-f( ) 调用-File的,因此传递给它的参数的解释可能会因情况而异 - 请参阅此答案


[1] 有一个有限的解决方法:执行策略仅与脚本文件有关,因此将脚本文件的内容读入内存并执行 - 无论是通过首先构建脚本块还是将其直接传递给通常避免Invoke-Expression- 是一种绕过主动执行策略的方法。一个简化的例子:
powershell -noprofile -c "Invoke-Expression (Get-Content -Raw c:\path\to\foo.ps1)". 也就是说,如果以这种方式执行的代码调用其他脚本文件,则该技术将不起作用,这也可能 在自动导入模块时隐式发生。

于 2022-03-04T03:00:25.567 回答