Windows PowerShell:共享您的脚本 - 轻松实现

Don Jones

Windows PowerShell v1 的一项限制是它不能轻松实现脚本共享。当然,您可以轻松将 .ps1 脚本文件复制到另一台计算机,甚至将其压缩起来并通过电子邮件发送给同事,可是早在十年前您就能对 VBScript 执行这样的操作了。但是如果您的脚本包含可重用的函数,收到该脚本的人就必须知道如何对其执行 dot-source 操作,否则就必须对其进行修改才能执行那些函数。

总而言之,虽然并不理想,但这种情况还是可以接受的。但是对于伴随着自定义格式视图或类型扩展的脚本而言,这种情况就不那么容易接受了,因为那些额外的文件不得不手动加载到 Shell 中,才能被脚本所使用。

而由于 Windows PowerShell v2 引入了模块,我们几乎实现了一种理想状况。

独立 Shell 块的优点

模块只不过是一组相互关联的文件。有两类广义的模块:二进制文件和脚本。

二进制模块包含一个或多个 DLL 文件,这些文件是从 C#、Visual Basic 等 Microsoft .NET Framework 语言编译生成的。在 v1 的时代,我们把这些文件称为 PSSnapin。事实上,Visual Studio 中编写这样的文件没有很大的变化。但是,管理单元还要求您编写一个安装程序,以便在 Shell 中注册您的 DLL。而对于模块,不需要进行安装。模块附带了一个 .psd1 文件 - 模块清单。清单只是一些 XML 代码,这些代码指示应该加载哪些 DLL。清单还可以指定附带的类型扩展文件 (.ps1xml) 或视图文件 (.format.ps1xml)。

下面介绍它的工作原理:模块必须安装在 Windows PowerShell \modules 文件夹的子目录中。默认情况下,此文件夹位于 c:\windows\system32\windowspowershell\v1.0\modules 中。因此,名为“MyModule”的模块将位于 c:\windows\system32\windowspowershell\v1.0\modules\mymodule 中,而其清单文件为 mymodule.psd1。与模块相关的任何文件通常分组放在同一个文件夹中,从而使所有内容均自我包含。

若要加载模块,您只需运行 Import-Module MyModule。默认情况下,Shell 将查看 \modules 文件夹(但如果您的模块位于其他位置,您也可以向 Import-Module 传递完整的路径),查看是否存在 .psd1 文件,读取该文件,并加载该文件中引用的文件。分发模块非常轻松:只需将所有文件压缩起来,并将 .zip 文件复制到另一台计算机,而无需进行安装。

动手创建自己的模块

那么,这如何帮助您更轻松地分发脚本?答案是第二种模块:脚本模块。这不过是一个普通的 Windows PowerShell 脚本,其文件扩展名为 .psm1,而不是一般的 .ps1。将 mymodule.psm1 放到 \modules 文件夹中之后,就可以运行 Import-Module MyModule,这将执行您的脚本。

通常,脚本模块完全由函数组成。也就是说,在导入该模块时,实际上不会执行任何操作,而仅仅将脚本模块中的函数加载到 Shell 中,并供整个 Shell 使用。假设您有一个类似下面的脚本模块:

Function Get-Inventory {
 # (some code goes here)
}
Function Test-Connectivity {
 # (some code goes here)
}
Function Write-Inventory {
 # (some code goes here)
}

导入此模块将使 Get-Inventory、Test-ConnectivityWrite-Inventory 函数可供整个 Shell 使用,就像 cmdlet 一样(事实上,我将在下个月讲解如何编写函数,使其几乎完全像“真的”cmdlet 一样)。您的函数甚至能包含基于注释的帮助(我在上一期专栏中进行了演示),这样其他人就可以导入该模块,并运行 Help Get-Inventory 来查看有关使用该函数的说明。

您有时需要一些私密性

有时您可能会拥有一个复杂的脚本模块,其中包含一些函数,仅供其他函数使用,而不由用户使用。例如,我可能希望 Test-ConnectivityWrite-Inventory 是模块所“私有”的。这意味着它们将被 Get-Inventory 调用,但我不希望它们直接被 Shell 用户调用。

默认情况下,Import-Module 会导入模块中的所有内容,从而使 Shell 用户能够看到所有函数。只需指定您希望对用户可见的函数列表,即可替代此行为;除了您指定的函数以外,Shell 用户将无法看到其他任何内容。为此,只需在脚本模块末尾执行 Export-ModuleMember

Export-ModuleMember –function Get-Inventory

如果需要,您还可以导出脚本中定义的 cmdlet、变量和别名。 有关详细信息,请运行 Help Export-ModuleMember 或查看 Export-ModuleMember

模块的不足

对于我来说,v2 模块唯一令人失望的是 Shell 似乎只有一个默认模块位置,而且该位置位于 Windows 系统文件夹下 - 您肯定不希望养成修改此文件夹的习惯。但是随后我查看了 PSModulePath 环境变量,并发现 Shell 还会查看您的“文档”文件夹(位于名为 WindowsPowerShell\Modules 的子文件夹中)。现在,我将我编写的所有模块都存放在该文件夹中。

将来,您很可能会看到 cmdlet 从基于 Internet 的资源库下载更多模块,而不像 Unix 系统中的 Pear 功能一样。这样的 cmdlet 更有可能会下载到您的“文档”文件夹或其他非操作系统的位置,因此让 Shell 在您的“文档”文件夹中搜索模块是一种相当聪明的默认设置。

到处都是模块

由于它们不需要安装就能被 Shell“看到”,因此模块的使用越来越多。事实上,在 Windows Server 2008 R2 中,几乎所有 Windows PowerShell 扩展都被封装为模块 - 唯一的例外是用于自动执行 Windows Server 备份的 PSSnapin(请运行 Get-PSSnapin –registered 来查看它是否安装在服务器上)。而以模块的形式发布的第三方代码更多,包括需要通过 PoshCode.org 访问社区代码资源库的 cmdlet。

事实上,如果您是一位经验丰富的 Windows PowerShell 用户,希望编写自己的 cmdlet,但是不希望深入研究 Visual Studio 中的 .NET Framework 编程,则高级函数(这是下个月的专栏主题)和模块的组合将使您能够完全用脚本来编写自己的 Shell 管理单元。只需将您的高级函数(外观和功能均与 cmdlet 一样)封装到脚本模块中,您就会得到一个易于分发的可重用代码库。

Windows PowerShell v2 现已公开推出

尽管它已经预装在 Windows Server 2008 R2 和 Windows 7 中,Windows PowerShell v2 及其附带的 Management Framework 组件现在已经可以在 Windows XP、Windows Server 2003、Windows Vista 和 Windows Server 2008 上使用。请访问 support.microsoft.com/kb/968929,以便获取针对您使用的操作系统的下载链接。在大多数情况下,这应该与您的 v1 脚本兼容;因此,我将来的专栏将假设您使用的是 2.0。

Don Jones是 Concentrated Technology 的创始人,他会在ConcentratedTech.com 解答有关 Windows PowerShell 和其他技术的问题。他还是Nexus.Realtimepublishers.com的撰稿人,并且他的许多著作还在此网站上以电子版的形式提供。

相关内容

     Windows PowerShell:PowerShell 和 Active Directory

     Windows PowerShell:筛选与格式“两头难”

     Windows PowerShell:始终关注