如何编写自定义 PowerShell Cmdlet - 第一部分






4.74/5 (10投票s)
如何编写自定义 PowerShell cmdlet。
引言
这是《如何编写自定义 PowerShell Cmdlet》系列文章的第一篇。我将尽量使这些文章直击要点,而不遗漏任何重要细节。对于微软文档中不甚清晰或可能缺失的内容,我将进行详细阐述。在大多数情况下,微软在 PowerShell 编程的 SDK 文档方面做得非常出色。
编写 PowerShell cmdlet 的第一步是确定你的 cmdlet 要做什么。这个 cmdlet 将带来什么价值?微软已经提供了许多方便系统管理和管理的 cmdlet。随着你对 PowerShell 的使用越来越多,你会发现通过 PowerShell 的管道架构,你可以做很多其他事情。在这篇文章中,我不会深入探讨 PowerShell 在系统管理和管理之外的其他用途。那将是另一天的讨论内容。在这篇文章中,我将解释你需要遵循的步骤来编写一个 PowerShell cmdlet。
我正在编写一个 cmdlet 来自动化搜索引擎 API 的测试。在这个 API 测试自动化的过程中,我意识到我可以使用这个 cmdlet 来执行大量的搜索,而无需使用 GUI,直接通过 PowerShell 就可以完成。并且,利用 Where-Object cmdlet,我可以将我的 cmdlet 的结果通过管道传递给它,然后进行过滤。你可以看到,组合一个快速的自定义 PowerShell cmdlet 用例并用它来简化许多任务是多么容易。当然,我不能发布我为我的搜索引擎开发的 cmdlet。但我想,我可以编写一个 cmdlet 来从 PowerShell 搜索 Amazon.com。所以,我将在我的 Amazon.com 的 C# API 的基础上开发我的 cmdlet。
Cmdlet 类
第一步是编写一个实现你的 cmdlet 核心功能的类。对于这篇基础文章和 cmdlet,我将不详细介绍你的类应该派生自 Cmdlet
还是 PSCmdlet
。在大多数情况下,你将派生自 Cmdlet
,除非你正在开发一个需要访问 PowerShell 运行时或需要执行与运行时相关的复杂任务的 cmdlet。选择 cmdlet 的名称非常重要。你的类名包含两个部分:动词(Verb)和名词(Noun)。动词定义了这个 cmdlet 将执行的操作,名词定义了动词作用的对象。例如,对于我的 cmdlet,我想要搜索 Amazon.com 上的书籍。所以,我的类名中的动词是“Search”或“Get”,名词是“Book”。所以我创建了一个名为 GetBookCommand
的类。你可能要问,为什么我没有称之为 GetBooksCommand
。根据微软的命名指南,为了保持名称的一致性,避免在名词中使用复数形式。
public class GetBookCommand : Cmdlet {...}
定义命令行参数
如果你的 cmdlet 可以在不使用任何输入参数的情况下执行其操作,那么你什么都不需要做。但是,如果你需要输入参数,那么你需要为这些参数在你的类中定义属性。而定义属性最重要的一部分是给它们命名。微软提供了一些命名属性的指南,以便你的 cmdlet 与所有其他 cmdlet 保持一致。有关更多详细信息,请参阅微软的 Cmdlet 参数名称 指南。
你需要决定的一个问题是哪些参数是强制性的,哪些参数是可选的,以执行你的 cmdlet。这时,在你的属性上使用 Parameter
属性就很重要了。这个属性类有一些属性,你可以用它们来微调参数的使用。例如,如果你想将你的参数标记为强制性的,你可以设置该属性的 Mandatory
属性。我将在我的 cmdlet 中通过使用这个属性来演示这一点。为了使我的 Get-Book
cmdlet 能够运行,用户必须提供以下四个命令行参数:
AssociateTag
AccessKey
SearchTerm
Count
所以,我在我的 cmdlet 类中为这些值定义了属性,并在它们上面添加了属性来将它们标记为强制性。下面的代码片段展示了 AssociateTag
属性的定义。
[Parameter(Mandatory = true,
HelpMessage="Specify associate tag issued by Amazon.com")]
[ValidateNotNullOrEmpty]
public string AssociateTag
{
get { return _associateTag; }
set{ _associateTag = value;}
}
注意属性上 Manadatory
和 HelpMessage
属性的使用。还请注意 ValidationNotNullOrEmpty
属性的使用。你可以使用验证属性来允许 PowerShell 运行时验证用户的输入。
重写方法
有四个方法可以让你重写以执行你的 cmdlet:BeginProcessing
、ProcessRecord
、EndProcessing
和 StopProcessing
。大多数 cmdlet 实现只需要关心 ProcessRecord
方法。这是你将处理你的输入对象并将其写入输出的地方。但是,如果你的 cmdlet 需要一些预处理或需要一些初始化,你可以在 BeforeProcessing
方法中重写它并在此处完成你的工作。例如,如果你正在实现一个需要在执行任何操作之前与数据库建立连接的 cmdlet,你可以在 BeginProcessing
中完成。并且,如果你在记录(record)处理后需要进行一些清理工作,你可以在 EndProcessing
方法中实现它并在此处进行清理。例如,如果你在 cmdlet 中打开了一个数据库连接,你可以在 EndProcessing
中始终实现清理工作。StopProcessing
的实现很重要,如果你在 cmdlet 中打开了需要清理的资源。如果由于某种原因,用户决定取消或停止你的 cmdlet,那么这个方法将给你一个清理的机会。否则,你将留下泄露的资源。下面的代码片段展示了我如何重写 BeginProcessing
方法来执行搜索。在实际实现中,我添加了一个方法来检查搜索数据的目标位置是否可用。如果目标 URL 不可用,就没有必要继续进行。
protected override void BeginProcessing()
{
base.BeginProcessing();
CreateDataAPI();
ExecuteSearch();
}
处理记录
PowerShell 运行时将调用你的 cmdlet 的 ProcessRecord
方法,允许你将你的 cmdlet 对象发送到输出。这是你可以组织需要显示的数据并调用 WriteObject
将它们发送到输出的地方。还有其他方法可以发送到输出。但是,在这篇文章中,我将保持实现简单,并调用 WriteObject
方法,让 PowerShell 运行时来处理我的记录的渲染。
protected override void ProcessRecord()
{
base.ProcessRecord();
foreach (Book book in _books)
{
WriteObject(book);
}
}
这就是你的 cmdlet 实现的结尾。你可以看到它有多么容易。我将在下一篇文章中介绍如何向 PowerShell 注册你的 cmdlet 以及其他一些好东西。同时,你可以从以下位置下载这个 cmdlet 的完整实现: