Windows PowerShell:打包并分发自定义 Windows PowerShell 工具
您可以利用 Dot-source 功能实现一些有趣的功能,但如果您不够谨慎,它也可能会带来一些问题。
Don Jones
Dot-source 是一种巧妙的技巧,但如果您不再需要某些命令,或者如果您后来发现某些命令与其他内容冲突,却很难删除这些命令。当我们在上个月将一个命令变为独立的、参数化的可重用工具之后,我发现我们需要解决两个问题。
我们将该工具构建为 Windows PowerShell 高级函数,有时也称为“脚本 Cmdlet”。第一个问题是,脚本本身难以使用。该脚本包含一个函数,因此如果只运行该脚本,不会发生任何事。您要么修改该脚本并添加用来运行该函数的命令,要么通过 Dot-source 将该脚本转移到 Shell 中,才能使该函数成为一个全局命令。
另一问题是,该脚本包含两个函数。第一个函数是 Get-OSInfo,是我希望用户使用的函数。第二个函数是 OSInfoWorker,它完成了所有实际的工作。但是,我不希望用户直接执行这个函数。如果使用 Dot-source 方式,则没有办法隐藏 OSInfoWorker(或者按照程序员的说法,将它变为私有)。将脚本转变成脚本模块可解决这两个问题。
了解模块
Windows PowerShell 支持三种基本的模块类型:二进制、脚本和清单模块。二进制模块包含一个在 Visual Studio 中生成的 DLL,用于向 Shell 添加 Cmdlet、提供程序或其他元素。脚本模块仅仅是指:单一的脚本,可向 Shell 添加一个或多个函数。清单模块可真正包含多个组件,例如二进制扩展程序、脚本等等。脚本模块最容易创建,因此我们选择使用脚本模块。
脚本模块有三项要求:
- 它必须是有效的 Windows PowerShell 脚本,主要由要添加到 Shell 中的函数组成。
- 它必须具有 .psm1 文件扩展名,而不是 .ps1 文件扩展名。
- 它必须位于计算机上的特定文件夹中
最后一条要求实际上不过是为方便起见而提供的一项建议。在安装时,Windows PowerShell 会定义一个新的系统级环境变量,名为 PSModulePath。此环境变量的工作方式与系统的 Path 环境变量非常相似。它包含 Shell 在按名称查找模块时自动搜索的文件夹。
默认情况下,会定义两个模块路径。其中一个位于 System32 文件夹层次结构下。此路径供 Microsoft 提供的模块使用。另一个位于您的 Documents 文件夹中,供您自己的模块使用。我们将使用这一个路径。当然,您可以在 PSModulePath 中修改或添加路径,例如,定义您的团队用来集中存储共享模块的路径。
我们使用的路径是 \[My ]Documents\WindowsPowerShell\Modules。在 Windows XP,此路径为“My Documents”。而在 Windows Vista 及更高版本中,此路径仅为“Documents”。默认情况下,WindowsPowerShell 文件夹不存在。您必须自行创建。默认情况下,Modules 子文件夹也不存在,因此您也需要自行创建。
如果不将您的模块放到某个 PSModulePath 位置中,则只需在加载模块时,指定完整的路径和文件名。这种方式对于常用模块不是很方便,因此我倾向于将其放到 PSModulePath 中定义的路径下。
构建模块
我将在上个月的脚本末尾加上三个命令(您可以在此下载修订后的脚本):
New-Alias goi Get-OSInfo
Export-ModuleMember -function Get-OSInfo
Export-ModuleMember -alias goi
第一个命令定义一个别名“goi”。它用于我的 Get-OSInfo 函数。其他两个命令仅当您在脚本模块中使用它们时才会生效。
默认情况下,当您将一个模块导入 Shell 中时,将公开提供该模块中的每个函数。但是当您使用 Export-ModuleMember 时,则只会公开提供那些明确命名的函数和别名。
我的“goi”别名以及 Get-OSInfo 函数就能由任何使用此模块的用户使用。而我未指定的函数 OSInfoWorker 将被隐藏。您仍然可以在模块本身内部使用任何函数来调用 OSInfoWorker,但它不能直接在模块外使用,因为它是私有函数。
添加了这些命令后,我需要为该脚本指定适当的名称并将其放到适当的位置。我选择将此模块命名为“MyModule”。因此,该脚本文件的路径应当为 \[My ]Documents\WindowsPowerShell\Modules\MyModule\MyModule.psm1。
该脚本必须放到 Modules 的子文件夹中。子文件夹和脚本文件本身的名称都必须与模块名相同。做完此操作后,我就可以运行 Import-Module MyModule 来加载我的模块。
这是向其他用户分发脚本的一种简单而又有效的方法。我可以根据需要,在这一个文件中包含任意数量的函数和别名。只要将其放到正确的位置(或者有人愿意指定完整路径),其他用户就能轻松加载该模块,并使用这些函数。
Don Jones是 Concentrated Technology 的创始人,他会在 ConcentratedTech.com 上解答有关 Windows PowerShell 和其他技术的问题。他也是 Nexus.Realtimepublishers.com 的撰稿人,他的许多著作还在他的网站上以电子版的形式提供。
获取更多内容
下载本月文章随附的示例代码。
注册即将截止,请赶快注册参加 Jones 亲自主持的独家动手体验工作室,该工作室为期三天,与 TechMentor Spring 2011 在同一地点举行。有关详情,请访问 TechMentorEvents.com。