如何配置Windows以更轻松地使用PowerShell脚本

Windows和PowerShell具有内置的安全功能和默认配置,旨在防止最终用户在日常活动过程中意外启动脚本。但是,如果您的日常活动经常涉及编写和运行您自己的PowerShell脚本,这可能会带来更多的麻烦而不是好处。在这里,我们将向您展示如何在不完全影响安全性的情况下解决这些功能。

Windows和PowerShell如何以及为什么阻止脚本执行。

PowerShell实际上是一种命令shell和脚本语言,旨在取代Windows系统上的CMD和批处理脚本。因此,PowerShell脚本几乎可以配置为执行您可以从命令行手动执行的任何操作。这等同于在您的系统上进行几乎任何可能的更改,直到您的用户帐户受到限制。因此,如果您只需双击PowerShell脚本并以完全管理员权限运行它,像这样的简单一行程序可能真的会毁了您的一天:

请勿运行上述命令!

这只需遍历文件系统并删除它能删除的任何内容。有趣的是,这可能不会像您想象的那样迅速使系统无法运行-即使在从提升的会话运行时也是如此。但是,如果有人在运行此脚本后打电话给您,因为他们突然找不到他们的文件或运行某些程序,“关闭并再次打开它”可能只会导致他们进入Windows启动修复,在那里他们将被告知无法采取任何措施来解决问题。更糟糕的是,你的朋友可能会被骗运行一个下载并安装键盘记录器或远程访问服务的脚本,而不是得到一个只会破坏他们文件系统的脚本。然后,他们可能会问警察一些关于银行诈骗的问题,而不是问你关于启动修复的问题!

到目前为止,可以说,为什么需要某些东西来保护最终用户免受其自身的伤害,这一点应该是显而易见的。但是高级用户、系统管理员和其他极客通常(尽管也有例外)对这些威胁更加警惕,他们知道如何发现并轻松避免这些威胁,并且只想继续完成他们的工作。要做到这一点,他们将不得不禁用或绕过几个路障:

默认情况下,PowerShell不允许执行外部脚本。 默认情况下,PowerShell中的ExecutionPolicy设置禁止在所有版本的Windows中执行外部脚本。在某些Windows版本中,默认情况下根本不允许执行脚本。我们在How to Allow the Execution of PowerShell Scripts on Windows7中向您展示了如何更改此设置,但我们也将在这里介绍几个级别的内容。 默认情况下,PowerShell与.PS1文件扩展名没有关联。 我们最初在PowerShell极客学校系列中提到了这一点。Windows将.PS1文件的默认操作设置为在记事本中打开它们,而不是将它们发送到PowerShell命令解释程序。这是为了直接防止恶意脚本在被简单双击时意外执行。 如果没有管理员权限,某些PowerShell脚本将无法运行。 即使使用管理员级别的帐户运行,您仍需要通过用户帐户控制(UAC)才能执行某些操作。对于命令行工具,至少可以说这可能有点麻烦。我们不想禁用UAC,但如果我们能让它更容易处理,这仍然是件好事。

在“如何使用批处理文件使PowerShell脚本更易于运行”一书中也提到了同样的问题,我们将向您介绍如何编写批处理文件以临时绕过它们。现在,我们将向您展示如何使用更长期的解决方案设置您的系统。请记住,您通常不应该在非您独家使用的系统上进行这些更改-否则,您会使其他用户面临更高的风险,从而遇到这些功能旨在防止的相同问题。

更改.PS1文件关联。

第一个也可能是最重要的麻烦是.PS1文件的默认关联。将这些文件与PowerShell.exe以外的任何文件相关联对于防止意外执行不需要的脚本很有意义。但是,考虑到PowerShell附带了专门为编辑PowerShell脚本而设计的集成脚本环境(ISE),我们为什么要在默认情况下在记事本中打开.PS1文件?即使您还没有准备好完全切换到启用双击即运行功能,您也可能希望调整这些设置。

您可以使用默认程序控制面板将.PS1文件关联更改为您想要的任何程序,但是直接深入注册表将使您能够更准确地控制文件将如何打开。这还允许您设置或更改.PS1文件的上下文菜单中提供的其他选项。在执行此操作之前,不要忘记备份注册表!

控制如何打开PowerShell脚本的注册表设置存储在以下位置:

要在进行更改之前研究这些设置,请使用regedit查看该键及其子键。Shell密钥应该只有一个值“(Default)”,它被设置为“Open”。这是指向双击文件的默认操作的指针,我们将在子键中看到。

展开Shell键,您将看到三个子键。其中每一个都表示您可以执行的特定于PowerShell脚本的操作。

您可以展开每个键以浏览其中的值,但它们基本上等同于以下默认值:

0-使用PowerShell运行。“使用PowerShell运行”实际上是PowerShell脚本的上下文菜单中已有的选项的名称。文本只是从另一个位置拉出,而不是像其他位置一样使用键名。而且这仍然不是默认的双击操作。 编辑-在PowerShell ISE中打开。这比记事本更有意义,但默认情况下,您仍然需要右键单击.PS1文件才能执行此操作。 打开-在记事本中打开。请注意,此键名称也是存储在Shell键的“(Default)”值中的字符串。这意味着双击该文件将“打开”它,并且该操作通常设置为使用记事本。

如果您想继续使用已有的预构建命令字符串,只需更改Shell键中的“(Default)”值,使其与您想要双击的键的名称相匹配。这可以很容易地从regedit中完成,或者您可以使用从我们的教程中学到的关于使用PowerShell探索注册表的经验(加上一个小的PSDrive调整)来开始构建一个可重用的脚本,该脚本可以为您配置您的系统。以下命令必须从提升的PowerShell会话运行,类似于以管理员身份运行CMD。

首先,您需要为HKEY_CLASSES_ROOT配置PSDrive,因为这不是默认设置。此操作的命令为:

现在,您可以在HKEY_CLASSES_ROOT中导航和编辑注册表项和值,就像在常规HKCU和HKLM PSDrive中一样。

要将双击配置为直接启动PowerShell脚本,请执行以下操作:

要配置双击以在PowerShell ISE中打开PowerShell脚本,请执行以下操作:

要恢复默认值(设置双击以在记事本中打开PowerShell脚本),请执行以下操作:

这只是更改默认双击操作的基础。在下一节中,我们将更详细地介绍如何自定义PowerShell脚本在PowerShell中从资源管理器中打开时的处理方式。请记住,作用域设置可防止PSDrive跨会话持久存在。因此,您可能希望在为此目的构建的任何配置脚本的开头包含New-PSDrive行,或者将其添加到PowerShell配置文件中。否则,在尝试以这种方式进行更改之前,您将需要手动运行该位。

更改PowerShell ExecutionPolicy设置。

PowerShell的ExecutionPolicy是针对恶意脚本执行的另一层保护。有多个选项可供选择,并且可以通过几种不同的方式进行设置。从最安全到最不安全,可用选项如下:

受限-不允许运行任何脚本。(大多数系统的默认设置。)。这甚至会阻止您的配置文件脚本运行。 AllSigned-所有脚本都必须由受信任的发布者进行数字签名,才能在不提示用户的情况下运行。由明确定义为不受信任的发布者签名的脚本或根本没有数字签名的脚本将不会运行。如果脚本由尚未定义为可信或不可信的发布者签名,PowerShell将提示用户确认。如果您没有对您的配置文件脚本进行数字签名,并建立了对该签名的信任,它将无法运行。注意您信任的发布者,因为如果您信任了错误的发布者,最终仍可能运行恶意脚本。 RemoteSigned-对于从Internet下载的脚本,这实际上等同于“AllSigned”。但是,允许在本地创建的脚本或从Internet以外的来源导入的脚本在没有任何确认提示的情况下运行。在这里,您还需要小心您信任的数字签名,甚至要更加小心您选择运行的未签名脚本。这是最高安全级别,在此级别下,您可以拥有有效的配置文件脚本,而无需对其进行数字签名。 无限制-允许运行所有脚本,但来自Internet的脚本需要确认提示。从现在开始,避免运行不值得信任的脚本完全取决于您。 旁路-一切都在没有警告的情况下运行。这件要小心。 未定义-未在当前作用域中定义任何策略。这用于允许回退到较低作用域中定义的策略(下面有更多详细信息)或操作系统默认值。

如未定义的描述所建议的,可以在几个作用域中的一个或多个中设置上述策略。您可以使用带有-list参数的Get-ExecutionPolicy来查看所有作用域及其当前配置。

作用域按优先顺序列出,最上面定义的作用域优先于所有其他作用域。如果未定义任何策略,系统将回退到其默认设置(在大多数情况下,这是受限制的)。

MachinePolicy表示在计算机级别生效的组策略。这通常只在域中应用,但也可以在本地完成。 UserPolicy代表对用户有效的组策略。这通常也仅在企业环境中使用。 进程是特定于此PowerShell实例的作用域。对此作用域中的策略所做的更改不会影响其他正在运行的PowerShell进程,并且在此会话终止后将无效。这可以在启动PowerShell时通过-ExecutionPolicy参数进行配置,也可以在会话中使用正确的Set-ExecutionPolicy语法进行设置。 CurrentUser是在本地注册表中配置的作用域,适用于用于启动PowerShell的用户帐户。可以使用Set-ExecutionPolicy修改此作用域。 LocalMachine是在本地注册表中配置并应用于系统上所有用户的作用域。如果运行Set-ExecutionPolicy时不使用-Scope参数,则这是更改的默认作用域。由于它适用于系统上的所有用户,因此只能从提升的会话进行更改。

由于本文主要是关于绕过安全性以促进可用性,因此我们只关注下面的三个范围。只有当您想要强制实施不是那么简单地绕过的限制性策略时,MachinePolicy和UserPolicy设置才真正有用。通过将更改保持在流程级别或更低级别,我们可以随时轻松地使用我们认为适合给定情况的任何策略设置。

为了在安全性和可用性之间保持一定的平衡,屏幕截图中显示的策略可能是最好的。将LocalMachine策略设置为“受限”通常会阻止除您之外的任何人运行脚本。当然,知道自己在做什么的用户可以省去这一点。但它应该可以防止任何不懂技术的用户意外地在PowerShell中触发灾难性的事情。将CurrentUser(即:您)设置为无限制允许您随心所欲地从命令行手动执行脚本,但会提醒您注意从Internet下载的脚本。进程级别的RemoteSigned设置需要在PowerShell.exe的快捷方式中或(如下所示)控制PowerShell脚本行为的注册表值中完成。这将为您编写的任何脚本提供轻松的双击即运行功能,同时为防止来自外部源的无意执行(潜在恶意)脚本设置更强的屏障。我们之所以在这里这样做,是因为意外双击脚本比通常从交互会话中手动调用要容易得多。

要如上面的屏幕截图所示设置CurrentUser和LocalMachine策略,请从提升的PowerShell会话运行以下命令:

要对从资源管理器运行的脚本实施RemoteSigned策略,我们必须更改前面查看的一个注册表项内的值。这一点特别重要,因为根据您的PowerShell或Windows版本,默认配置可能是绕过除AllSigned之外的所有ExecutionPolicy设置。要查看您计算机的当前配置,您可以运行此命令(确保首先映射HKCR PSDrive):

您的默认配置可能是以下两个字符串之一,或者非常类似的配置:

(在装有PowerShell 2.0的Windows 7 SP1 x64上显示)

(在装有PowerShell 4.0的Windows 8.1 x64上显示)

第一个并不太差,因为它所做的全部工作就是在现有的ExecutionPolicy设置下执行脚本。可以通过对更容易发生事故的操作实施更严格的限制来使其变得更好,但这本来并不打算在双击时触发,而且默认策略毕竟通常是受限制的。然而,第二种选择是完全绕过您可能拥有的任何ExecutionPolicy-即使是受限的。由于绕过将应用于进程范围,因此它仅影响从资源管理器运行脚本时启动的会话。但是,这意味着您最终可能会启动原本预期(并希望)您的策略禁止的脚本。

要为从资源管理器启动的脚本设置进程级ExecutionPolicy,与上面的屏幕截图一致,您需要修改我们刚刚查询的注册表值。您可以在regedit中手动执行此操作,方法是将其更改为以下内容:

如果愿意,您也可以在PowerShell中更改设置。请记住,在映射了HKCR PSDrive的情况下,在提升的会话中执行此操作。

以管理员身份运行PowerShell脚本。

正如完全禁用UAC不是一个好主意一样,使用提升的权限运行脚本或程序也是不好的安全做法,除非您确实需要他们执行需要管理员访问权限的操作。因此,不建议将UAC提示符构建为PowerShell脚本的默认操作。但是,我们可以添加一个新的上下文菜单选项,以便在需要时在提升的会话中轻松运行脚本。这类似于将“用记事本打开”添加到所有文件的上下文菜单中的方法-但这里我们只针对PowerShell脚本。我们还将继续使用上一篇文章中使用的一些技术,在上一篇文章中,我们使用批处理文件而不是注册表黑客来启动PowerShell脚本。

要在regedit中执行此操作,请在以下位置返回Shell密钥:

在那里,创建一个新的子密钥。将其称为“使用PowerShell(Admin)运行(Run with PowerShell(Admin)”)。在此基础上,创建另一个名为“Command”的子键。然后,将Command下的“(Default)”值设置为以下值:

在PowerShell中执行同样的操作,这一次实际上需要三行代码。一个用于每个新键,一个用于设置Command的“(Default)”值。别忘了高程和香港铁路的地图。

此外,请仔细注意通过PowerShell输入的字符串与进入注册表的实际值之间的差异。特别是,我们必须将整个内容括在单引号中,并在内部单引号上使用双引号,以避免命令解析中出现错误。

现在,您应该有一个新的PowerShell脚本上下文菜单项,名为“Run with PowerShell(Admin)”。

新选项将生成两个连续的PowerShell实例。第一个只是第二个的启动器,它使用带有“-verb Runas”参数的start-process来请求新会话的提升。在那里,在单击UAC提示符后,您的脚本应该能够以管理员权限运行。

最后的润色。

只需对此再做几个调整,就可以让生活变得更轻松一些。首先,完全取消记事本功能怎么样?只需将“(Default)”值从“编辑”(下图)下的Command键复制到“打开”下的相同位置即可。

或者,您可以使用这一位PowerShell(当然与Admin和HKCR一起使用):

另一个小麻烦是,一旦脚本完成,控制台的习惯就会消失。当发生这种情况时,我们没有任何机会检查脚本输出中的错误或其他有用信息。当然,这可以通过在每个脚本的末尾加一个暂停来解决。或者,我们可以修改Command键的“(Default)”值,使其包含“-noexit”参数。以下是修改后的值。

(没有管理员访问权限)

(具有管理员访问权限)

当然,我们也会在PowerShell命令中为您提供这些。最后提醒:Elevation&HKCR!

(非管理员)

(管理员)

开着它兜风。

为了测试这一点,我们将使用一个脚本,该脚本可以显示ExecutionPolicy设置是否到位,以及该脚本是否以管理员权限启动。该脚本将被命名为“MyScript.ps1”,并存储在我们的示例系统上的“D:\Script Lab”中。代码如下,供参考。

使用“使用PowerShell运行”操作:

在通过UAC单击之后,使用“Run with PowerShell(Admin)”(使用PowerShell(Admin)运行)操作:

为了在进程范围内演示ExecutionPolicy的实际操作,我们可以使用下面这段PowerShell代码让Windows认为该文件来自Internet:

幸运的是,我们没有启用-noexit。否则,这个错误就会转瞬即逝,我们也不会知道!

可以使用以下命令删除Zone.Identifier:

有用的参考资料:

从批处理文件运行PowerShell脚本-Daniel Schroeder的编程博客。 正在检查PowerShell中的管理员权限-嗨,脚本编写人员!博客

相关文章