如何使用批处理文件使PowerShell脚本更易于运行

由于几个主要与安全相关的原因,PowerShell脚本不像批处理脚本那样容易移植和使用。但是,我们可以将批处理脚本与PowerShell脚本捆绑在一起来解决这些问题。在这里,我们将向您展示其中的几个问题区域,以及如何构建批处理脚本来绕过它们。

为什么我不能直接将.PS1文件复制到另一台计算机并运行它?

除非已将目标系统预先配置为允许以所需的权限和使用正确的设置运行任意脚本,否则在尝试执行此操作时很可能会遇到一些问题。

默认情况下,PowerShell与.PS1文件扩展名没有关联。 我们最初在PowerShell极客学校系列中提到了这一点。默认情况下,Windows会将.PS1文件与记事本关联,而不是将它们发送到PowerShell命令解释程序。这是为了防止只需双击恶意脚本即可意外执行。有一些方法可以更改此行为,但您可能不想在您随身携带脚本的每台计算机上这样做-特别是当其中一些计算机不是您自己的计算机时。 默认情况下,PowerShell不允许执行外部脚本。 默认情况下,PowerShell中的ExecutionPolicy设置禁止在所有版本的Windows中执行外部脚本。在某些Windows版本中,默认情况下根本不允许执行脚本。我们在如何允许在Windows 7上执行PowerShell脚本中向您展示了如何更改此设置。但是,这也是您不希望在任何计算机上执行的操作。 如果没有管理员权限,某些PowerShell脚本将无法运行。 即使使用管理员级别的帐户运行,您仍需要通过用户帐户控制(UAC)才能执行某些操作。我们不想禁用它,但如果我们能让它更容易处理,这仍然是件好事。 某些用户可能具有自定义的PowerShell环境。 您可能不会经常遇到这种情况,但是当您这样做时,可能会使运行脚本和排除脚本故障变得有点令人沮丧。幸运的是,我们可以在不做任何永久性更改的情况下绕过这一问题。

第一步:双击运行。

让我们首先解决第一个问题-.PS1文件关联。您不能双击来运行.PS1文件,但可以通过这种方式执行.bat文件。因此,我们将编写一个批处理文件来从命令行调用PowerShell脚本。

因此,我们不必为每个脚本重写批处理文件,或者每次移动脚本时,它都会使用自引用变量来构建PowerShell脚本的文件路径。要执行此操作,批处理文件需要放置在与PowerShell脚本相同的文件夹中,并且具有相同的文件名。因此,如果您的PowerShell脚本名为“MyScript.ps1”,您需要将批处理文件命名为“MyScript.bat”,并确保它位于同一文件夹中。然后,将以下行放入批处理脚本中:

如果没有其他安全限制,从批处理文件运行PowerShell脚本就真的只需要这么多了。事实上,第一行和最后一行主要是一个偏好问题--真正起作用的是第二行。以下是细目:

@ECHO OFF关闭命令回显。这只会在批处理文件运行时阻止您的其他命令显示在屏幕上。这行本身通过在其前面使用at(@)符号来隐藏。

PowerShell.exe-Command“&‘%~dpn0.ps1’”实际上运行PowerShell脚本。当然,可以从任何CMD窗口或批处理文件调用PowerShell.exe,以便像往常一样将PowerShell启动到空控制台。通过包括-Command参数和适当的参数,您还可以使用它直接从批处理文件运行命令。它用于指向我们的.PS1文件的方式是使用特殊的%~dpn0变量。从批处理文件运行,%~dpn0计算为批处理文件的驱动器号、文件夹路径和文件名(不带扩展名)。由于批处理文件和PowerShell脚本将位于同一文件夹中且名称相同,因此%~dpn0.ps1将转换为PowerShell脚本的完整文件路径。

暂停只是暂停批处理执行并等待用户输入。这通常对批处理文件的末尾有帮助,这样您就有机会在窗口消失之前查看任何命令输出。随着我们通过每一步的测试,这一点的用处将变得更加明显。

这样,就建立了基本的批处理文件。出于演示目的,此文件另存为“D:\Script Lab\MyScript.bat”,同一文件夹中有一个“MyScript.ps1”。让我们看看当我们双击MyScript.bat时会发生什么。

显然PowerShell脚本没有运行,但这是意料之中的-毕竟我们只解决了四个问题中的第一个问题。但是,这里演示了一些重要的部分:

窗口标题显示批处理脚本已成功启动PowerShell。 第一行输出显示正在使用自定义PowerShell配置文件。这是上面列出的潜在问题#4。 该错误消息说明生效的ExecutionPolicy限制。这是我们的第二个问题。 错误消息中带下划线的部分(由PowerShell的错误输出本机完成)表明批处理脚本已正确指向预期的PowerShell脚本(D:\Script Lab\MyScript.ps1)。所以我们至少知道很多都在正常工作。

在本例中,概要文件是一个简单的单行脚本,用于此演示,以便在概要文件处于活动状态时生成输出。如果您想自己测试这些脚本,您也可以自定义您自己的PowerShell配置文件来执行此操作。只需将以下行添加到您的配置文件脚本中:

此处测试系统上的ExecutionPolicy设置为RemoteSigned。这允许执行本地创建的脚本(如配置文件脚本),同时阻止来自外部来源的脚本,除非它们由受信任的机构签名。出于演示目的,使用以下命令将MyScript.ps1标记为来自外部源:

这将在MyScript.ps1上设置Zone.Identifier备用数据流,这样Windows就会认为该文件来自Internet。可以使用以下命令轻松地反转:

步骤2:绕过ExecutionPolicy。

从CMD或批处理脚本绕过ExecutionPolicy设置实际上相当容易。我们只需修改脚本的第二行,为PowerShell.exe命令再添加一个参数。

-ExecutionPolicy参数可用于修改在派生新PowerShell会话时使用的ExecutionPolicy。这将不会持续到该会话之后,因此我们可以在需要的任何时候像这样运行PowerShell,而不会削弱系统的总体安全状态。现在我们已经解决了这个问题,让我们再来一次:

现在脚本已经正确执行,我们可以看到它实际做了什么。它让我们知道我们是以受限用户身份运行脚本的。该脚本实际上是由具有管理员权限的帐户运行的,但是用户帐户控制阻碍了运行。尽管有关脚本如何检查管理员访问权限的详细信息超出了本文的范围,但以下是用于演示的代码:

您还会注意到,脚本输出中现在有两个“暂停”操作-一个来自PowerShell脚本,另一个来自批处理文件。这样做的原因在下一步会更加明显。

步骤3:获取管理员访问权限。

如果您的脚本不运行任何需要提升的命令,并且您非常确定您不必担心任何人的自定义配置文件会妨碍您,那么您可以跳过其余的步骤。但是,如果您正在运行一些管理员级别的cmdlet,您将需要这一部分。

不幸的是,无法从批处理文件或CMD会话中触发UAC进行提升。但是,PowerShell确实允许我们使用start-process来实现这一点。当在其参数中使用“-verb RunAs”时,Start-Process将尝试使用管理员权限启动应用程序。如果PowerShell会话尚未提升,这将触发UAC提示。要从批处理文件中使用它来启动我们的脚本,我们将最终派生两个PowerShell进程-一个用于启动start-process,另一个由start-process启动以运行脚本。批处理文件的第二行需要更改为:

运行批处理文件时,我们将看到的第一行输出来自PowerShell配置文件脚本。然后,当start-process尝试启动MyScript.ps1时会出现UAC提示。

单击UAC提示符后,将生成一个新的PowerShell实例。因为这是一个新实例,当然,我们将再次看到配置文件脚本通知。然后,MyScript.ps1运行,我们看到我们确实处于提升的会话中。

这也是我们在这里有两个停顿的原因。如果不是PowerShell脚本中的那个,我们永远看不到脚本的输出-脚本一运行完毕,PowerShell窗口就会弹出并消失。如果批处理文件中没有暂停,我们将无法首先查看启动PowerShell时是否有任何错误。

步骤4:绕过自定义PowerShell配置文件。

我们现在就把那个讨厌的客户简介通知去掉,好吗?在这里,它甚至算不上麻烦,但是如果用户的PowerShell配置文件以您可能没有预料到的方式更改脚本的默认设置、变量或函数,那么它们可能真的很麻烦。完全不使用配置文件运行脚本要简单得多,因此您不必担心这一点。为此,我们只需再次更改批处理文件的第二行:

将-NoProfile参数添加到由脚本启动的两个PowerShell实例意味着在这两个步骤中都将完全绕过用户的配置文件脚本,并且PowerShell脚本将在相当可预测的默认环境中运行。在这里,您可以看到在两个派生的shell中都没有自定义配置文件通知。

如果在PowerShell脚本中不需要管理员权限,并且已跳过步骤3,则可以不使用第二个PowerShell实例,批处理文件的第二行应如下所示:

然后,输出将如下所示:

(当然,对于非管理员脚本,此时PowerShell脚本中也可以没有脚本结束暂停,因为所有内容都捕获在同一个控制台窗口中,并且无论如何都会通过批处理文件末尾的暂停保留在那里。)

已完成的批处理文件。

根据您是否需要PowerShell脚本的管理员权限(如果不需要,您确实不应该请求管理员权限),最终的批处理文件应该类似于以下两种权限之一。

没有管理员访问权限:

具有管理员访问权限:

请记住将批处理文件放在与要使用它的PowerShell脚本相同的文件夹中,并为其指定相同的名称。然后,无论您将这些文件带到哪个系统,您都可以运行PowerShell脚本,而不必更改系统上的任何安全设置。当然,您每次都可以手动进行这些更改,但这省去了您的麻烦,而且您不必担心稍后恢复更改。

参考资料:

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

相关文章