你曾经下载过一个 PowerShell 脚本,运行它,然后遇到下面那个臭名昭著的错误消息吗?如果是的话,你需要使用 Set-ExecutionPolicy 命令和本教程!

在本文中,你将学习有关 PowerShell 执行策略以及如何使用 Set-ExecutionPolicy 命令来管理它们。在本文结束时,你不仅将知道如何运行脚本,还将了解如何使用执行策略!
本教程是针对 Windows PowerShell 编写的,并且所有演示都是在 Windows PowerShell 上执行的。执行策略并不局限于 Windows PowerShell,在 PowerShell 6+ 中的操作方式非常相似。但是,如果你使用的是 PowerShell 6+,你可能会发现行为上存在一些小差异。
什么是执行策略?
如果你曾经遇到过上面描述的错误,那么你就碰到过执行策略了。PowerShell 执行策略是一种安全机制,用于保护系统免受运行恶意脚本的影响。执行策略不会阻止你在控制台中作为 shell 运行 PowerShell 代码,但会影响脚本的执行。脚本
微软表示,执行策略在技术上并不是一种“安全”措施,而更像是你可以打开和关闭的大门。毕竟,你可以轻松地绕过已定义的执行策略,正如你后面将学到的那样。
执行策略基于信任。如果你信任一个脚本,很可能它是没有恶意的。执行策略通常不会阻止所有脚本的执行。它们的主要目的(特别是在更严格的配置下)是确保你信任你要运行的脚本是使用证书进行了密码学签名。
执行策略范围
正如你了解到的,执行策略限制脚本的执行,但PowerShell可以在许多不同的上下文中执行脚本。PowerShell以用户已登录的上下文或全局机器上下文执行脚本,通过以SYSTEM身份运行的计划任务或在单个打开的PowerShell控制台范围内执行。
为了适应所有这些上下文,PowerShell有五个不同的上下文或范围,你可以定义执行策略。
- MachinePolicy – 此范围限于单台计算机。它影响登录到该计算机的所有用户,并由Active Directory组策略对象设置。定义时,它优先于所有其他范围。
- 本地计算机。这是影响所有计算机用户的默认范围,存储在HKEY_LOCAL_MACHINE注册表子键中。当您使用
Set-ExecutionPolicy
设置执行策略时,该范围是默认的。
本地计算机的执行策略存储在注册表键HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell中。
- UserPolicy – UserPolicy范围仅影响计算机上的单个用户,并由Active Directory组策略对象设置。您无法使用
Set-ExecutionPolicy
更改此策略。 - 当前用户。当前用户策略范围仅为当前用户设置执行策略,并存储在HKEY_CURRENT_USER注册表子键下。您无法使用
Set-ExecutionPolicy
更改此策略。
当前用户的执行策略存储在注册表键HKEY_CURRENT_USER\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell中。
- 进程 – 此范围为单个用户的单个PowerShell会话定义执行策略。进程执行策略范围是您可以定义的最细粒度的执行策略。与其他执行策略不同,此策略保存在名为
PSExecutionPolicyPreference
的环境变量中,而不是注册表中。
执行策略类型
执行策略有各种“安全级别”。这些级别规定了执行策略的严格程度。例如,您可以设置一个基本上什么都不做的执行策略;它被禁用,但另一方面,执行策略也可以完全禁用脚本执行。
让我们逐一介绍如何配置执行策略的安全级别,从最不严格到最严格。
不受限制
最不受限制的策略是完全不受限制的策略;它是不受限制。 不受限制执行策略基本上是禁用的。当执行策略是不受限制时,用户可以运行所有脚本,而不考虑信任。
绕过
与不受限制类型类似,将执行策略设置为绕过不阻止任何内容。
虽然绕过和不受限制具有类似的效果,但绕过执行策略类型在技术上实际上不是一种类型。它完全跳过了定义的执行策略。
未定义
虽然不常用,但您可以通过将执行策略设置为未定义来基本上删除执行策略。当将执行策略设置为未定义时,PowerShell会从分配的范围中完全删除任何已分配的执行策略。
在非Windows计算机上,执行策略始终设置为不受限制,无法更改。
当所有范围都设置为未定义时,PowerShell基本上将所有范围视为受限制的。
远程签名
如你之前阅读的,执行策略主要是通过脚本的数字签名获得的信任。PowerShell也考虑到脚本来自何处。它是在你的本地计算机上创建的,还是来自互联网上的某个随机人士?
在你的本地计算机之外的地方构建的脚本不应被默认信任。这就是为什么PowerShell提供了RemoteSigned执行策略。RemoteSigned执行策略要求在你的本地计算机以外的地方编写的所有脚本都必须进行加密签名。
你可以在一定程度上覆盖这种执行策略,对来自互联网的下载文件使用
Unblock-File
cmdlet。在稍后的“RemoteSigned策略如何工作”部分,你可以获取更多关于这种行为的信息。
对于Windows服务器,RemoteSigned被设定为默认策略。
AllSigned
如果你想确保所有PowerShell脚本都进行了加密签名,可以将执行策略设置为AllSigned。像RemoteSigned一样,这种执行策略更进一步要求所有脚本在执行前都要签名。
即使你设置了AllSigned执行策略,你仍然可以通过绕过它来避开执行策略,你稍后会学到。
Restricted
最严格的执行策略是Restricted。当执行策略设置为Restricted时,绝对不允许执行任何脚本,无论它们是否受信任。该策略基本上完全禁用脚本执行。
而且,与较不限制的类型不同,Restricted类型确保 PowerShell 格式和配置文件(PS1XML)、模块脚本文件(PSM1)以及 PowerShell 配置文件无法执行。
所有 Windows 客户端,默认情况下都设置为Restricted执行策略。
在技术上,Microsoft 定义了第七个执行策略,称为 Default,但该类型实质上只是 RemoteSigned(Windows Server)和 Restricted(Windows 客户端)的另一个标签。
RemoteSigned 策略的工作原理
要指出的一个特定场景是RemoteSigned执行策略的工作原理。正如你所了解的,该执行策略阻止运行在本地计算机以外的地方创建的脚本。
但是 PowerShell 如何知道脚本是在其他地方创建的呢?数据流。
了解和查询 NTFS 数据流
每当在NTFS 文件系统上创建文件时,NTFS 将一个alternate data stream(ADS)属性应用于文件。ADS 有两个文件属性:$Data 和 zone.Identifier。PowerShell 使用zone.Identifier属性来确定 PowerShell 脚本文件是否是在其他地方创建的。
与压缩或只读等其他属性不同,ADS属性在文件资源管理器中是隐藏的。但是,通过使用PowerShell,您可以检查这些数据流。
运行Get-Item
cmdlet,并使用脚本路径和Stream
参数,如下所示。在这个例子中,Hello World.ps1是在本地计算机上编写的。注意分配给Stream
属性的唯一属性是$DATA
。没有ADS属性。

现在,对从互联网下载的脚本运行相同的命令。现在注意Get-Item
返回另一个完全不同的对象,具有Stream
为Zone.Identifier
。

一旦您知道文件有ADS,您就可以使用Get-Content
命令来发现区域。区域定义文件来自何处。
Get-Content
将返回一个ZoneId
值,表示文件来自的区域。

可能的区域值有:
执行策略优先级
如上所述,同时存在许多不同的执行策略。所有这些执行策略在组合时会决定当前会话的设置。当您有多个执行策略生效时,必须有优先级。
策略优先级是PowerShell应用于不同范围设置的顺序。某些执行策略的优先级高于其他执行策略。
当你运行Get-ExecutionPolicy -List
时,你将找到当前生效的所有执行策略,按优先级从低到高排序。例如,由于MachinePolicy的优先级较低,LocalMachine和CurrentUser策略将覆盖它。

处理执行策略
在了解执行策略背景足够的基础上,让我们深入了解如何与它们一起工作!要处理PowerShell的执行策略,你有两个可用的命令:Get-ExecutionPolicy
用于查看当前定义的策略,以及Set-ExecutionPolicy
用于设置新策略。
获取当前分配的策略
在开始更改执行策略之前,你需要了解正在处理的内容。为此,你可以使用Get-ExecutionPolicy
命令。该命令列举了计算机上当前分配的所有策略。
当你在PowerShell控制台上直接运行Get-ExecutionPolicy
命令且没有参数时,它将显示为当前PowerShell会话设置的执行策略。

要查看设置为某个范围的执行策略,请使用Scope
参数并指定要查看结果的范围名称。

要查看所有范围及其执行策略,请使用如下所示的List
参数。

更改执行策略
一旦您了解当前分配的执行策略,您也可以进行更改。要在单台计算机上更改策略,您可以使用Set-ExecutionPolicy
命令。但是,如果您在组织中,您可能希望批量更改策略。如果是这种情况,如果您在Active Directory域中,您始终可以使用组策略。
使用Set-ExecutionPolicy
首先让我们讨论如何使用Set-ExecutionPolicy
命令更改策略。为此,请以管理员身份打开PowerShell。
现在运行Set-ExecutionPolicy
命令,并提供一个参数(ExecutionPolicy
),指定执行策略的名称。
然后,PowerShell将询问您是否要更改执行策略。如果是,请键入Y或A,然后按Enter。

一些PowerShell命令需要运行多个其他任务才能操作。在上面的示例中,如果您输入Y
,PowerShell可能会提示您为每个步骤继续操作。如果您按A
,它将继续所有后续步骤。
无需提示运行Set-ExecutionPolicy
默认情况下,当您运行Set-ExecutionPolicy
时,它会提示您是否要更改执行策略。您可以通过向您的命令添加Force
参数来跳过此提示。使用Force
参数将抑制所有确认提示。

通过注册表设置PowerShell执行策略
由于大多数执行策略都存储在注册表中(不包括Process),您也可以直接通过注册表更改策略。
要通过注册表更改执行策略:
- 打开Windows注册表编辑器(regedit)或您选择的注册表编辑工具。
2. 导航到您想要更改的执行策略范围的注册表键。
LocalMachine – HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell
CurrentUser – HKEY_CURRENT_USER\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell
3. 右键单击注册表键并创建一个名为ExecutionPolicy的新字符串值。
4. 双击新创建的ExecutionPolicy字符串值,并输入所需的执行策略名称(Restricted、RemoteSigned、AllSigned、Unrestricted或Undefined)。
5. 在同一键中创建另一个字符串值,称为Path。 Path字符串值表示到PowerShell引擎的路径。确保Path值为C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe,指向Windows PowerShell引擎。

CurrentUser执行策略覆盖LocalMachine策略。如果在注册表中设置了CurrentUser策略,并尝试通过Set-ExecutionPolicy
更改执行策略,默认情况下会将策略设置为LocalMachine范围,PowerShell将返回以下错误。

通过组策略设置PowerShell执行策略
如果您在具有Active Directory的组织中,您不会想要在所有Windows机器上运行Set-ExecutionPolicy
cmdlet。相反,您可以使用组策略批量管理策略。
通过GPO管理执行策略:
创建组策略对象
- 在域控制器或域加入的工作站上打开组策略管理应用程序。

2. 展开域 —> <您的Active Directory森林> —> 组策略对象。

3. 右键单击组策略对象,然后单击新建。
4. 给你的GPO取一个名字。在本教程中,GPO被称为PowerShell执行策略。

5. 右键单击新创建的GPO,然后单击编辑。
6. 转到计算机配置\Policies\Administrative Templates\Windows 组件\Windows PowerShell。

7. 在右窗格中打开设置,打开打开脚本执行设置。

8. 在打开脚本执行框中,选择已启用选项。您现在可以从下面显示的选项中选择任何一个:
9. 现在将执行策略更改为您所需的策略。
- 仅允许签名脚本 – 当受信任的发布者对其进行签名时,允许执行所有脚本。
- 允许本地脚本和远程签名脚本 – 允许运行本地脚本,但从互联网下载的脚本应由受信任的发布者签名。
- 允许所有脚本 – 允许运行所有脚本。

分配组策略对象
创建了GPO之后,现在是将其分配给目标计算机的时候了。为此,您必须将GPO分配给活动目录组织单位(OU)。
如果您编辑了现有的GPO而不是创建新的GPO,则该GPO很可能已经被分配给了OU。
- 在 组策略管理 中,通过以下步骤导航到您选择的组织单位:域 —> <您的活动目录森林> —> <您的组织单位>。
2. 右键单击该组织单位,然后选择 链接现有的 GPO…

3. 选择刚创建的 GPO(PowerShell 执行策略),然后点击 确定。

现在,您应该可以看到已将 GPO 分配给该组织单位,如下所示。

此时,您可以等待定义的 组策略刷新间隔,或在目标计算机上运行 gpupdate 命令来强制刷新。
锁定本地策略更改
一旦生效了更改执行策略的 GPO,本地用户就无法再通过本地 PowerShell 控制台更改策略。如果尝试,将收到如下错误提示。

完全绕过执行策略
如前所述,执行策略并不一定意味着是一种安全措施。为什么?因为您可以通过几种不同的方式完全绕过它。
使用 -ExecutionPolicy Bypass
参数
与其他执行策略不同,Bypass策略通常不是在PowerShell控制台中设置,而是传递给以管理员身份运行的powershell.exe引擎。
例如,要运行名为Hello World.ps1的脚本,完全跳过任何执行策略,调用powershell.exe,使用Bypass
参数,并提供文件路径如下所示。

读取脚本和执行原始代码
您还可以通过首先读取脚本的内容,然后将该内容直接传递给PowerShell引擎来避开任何执行策略。这样做会将每个命令分别运行,而不是一次性运行整个脚本。
正如您下面所见,执行策略设置为Restricted,但通过读取脚本并将其传递给powershell.exe,它仍然可以工作。
这种方法类似于在PowerShell编辑器(如PowerShell ISE或Visual Studio Code)中打开脚本,选择一行并按下F8。

结论
到目前为止,您应该了解了有关PowerShell执行策略的所有内容。尽管它们在技术上不是安全措施,但您仍应根据组织政策来管理它们。