Windows PowerShell前景看好

Don Jones

我们往往希望脚本生成规范的输出,也经常有人问我怎样才是生成规范输出(如表)的最好方法。这种方法的确有很多种。第一步是编写脚本,将要以格式化形式显示的任何数据放置在

$data1、$data2 和 $data3 变量中。现在,可以着手格式化数据。

文本方式

网上

是否正在寻找本月 Windows PowerShell 专栏中讨论的技术快速演示?请转到 technetmagazine.com/video 以查看 Don Jones 对这些 cmdlet 的演示。

人们处理此任务最常见的方式就是像使用一种语言(如 VBScript、Perl、KiXtart 或其他面向文本的语言)对其进行处理一样。首先,我可以在屏幕上写出一组列标题:

Write-Host "ColumnA'tColumnB'tColumnC"

请注意,在 Windows PowerShellTM 中,`t 是一个特殊转义符序列,表示插入一个制表符。要编写表的每一行(如前所述,我的数据位于 $data1、$data2 和 $data3),我有多种方法可供选择。一种方法是只写入变量,依赖 shell 的功能用双引号内的内容替换变量:

Write-Host "$data1't$data2't$data3"

另外一种稍微吸引人的方法是使用 f 运算符来实现。此方法将格式与数据分开,可以用以下更加易读和维护的代码行来表示:

Write-Host "{0}'t{1}'t{3}" –f $data1,$data2,$data3

不过,整个方法有一些重大问题。首先,如果依靠控制台窗口中的固定制表位,则我必须自己处理一些奇怪的格式。例如,如果第一列中某个特殊表行有一个包含 20 个字符的值,则我不得不对该行全部应用这种格式。此外,由于我使用 Write-Host 输出这些文本,因此几乎只能看到控制台显示。

将输出发送到文件或将其放在其他格式中并没有简单方法,尽管我一直期望有这样的简单方法。最重要的是,这种基于文本的方法完全忽略了我正在使用的在本质上基于对象的 shell,从而无法利用 Windows PowerShell 提供的各种强大的技术和功能。

Windows PowerShell 方式

Windows PowerShell 是面向对象的 shell。这就意味着在理想情况下,您处理的所有内容都应该在对象中,从而 shell 可以在需要时将其转换为文本显示。但是,如何为任意数据片段创建对象?

仍采用我的示例,我首先创建一个空白自定义对象并将其存储在变量中:

 $obj = New-Object PSObject

这样,我们就获得了一个全新的空白对象。然后,以属性形式向该对象中添加数据。为此,我仅将对象以管道形式传递到 Add-Member cmdlet 中。我添加了一个名为 NoteProperty 的属性并为该属性命名(最好使用列标题作为属性名称),然后,插入数据作为属性值:

 $obj | Add-Member NotePropertyColumnA $data1
$obj | Add-Member NotePropertyColumnB $data2
$obj | Add-Member NotePropertyColumnC $data3

现在,仅将该对象输出到管道(而不是控制台):

Write-Output $obj

然后,可以对需要输出的每个表行重复这些步骤。以下简短函数的作用是接受一个字符串并输出其大写字母和小写字母版本以及原始字符串:

functionStringVersions {
param([string]$inputString)
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Original($inputString)
  $obj | Add-Member NoteProperty Uppercase($inputString.ToUpper())
  $obj | Add-Member NoteProperty Lowercase($inputString.ToLower())
  Write-Output $obj
}  
$strings = @("one","two","three")
foreach ($item in $strings) {
StringVersions $item
}

以字符串变量的数组开始,一次处理一个变量并将其发送到函数中。该函数的输出被写入管道中。

请注意,此代码可以编写得更简单些,但以上代码更能清楚地说明我阐述的要点。其结果是一个格式相当完美的表,如图 1 中所示。这是因为 shell 已经知道如何在表中格式化对象。

图 1 以表形式显示的 Windows PowerShell 输出

图 1** 以表形式显示的 Windows PowerShell 输出 **(单击该图像获得较大视图)

只要对象有四个或更少的属性,Windows PowerShell 就会自动选择表。因此,我无需自己执行任何操作,就获得了一个规范的表。

不过,请等一下,还有其他功能!

本月 Cmdlet:Get-Command

我相信您曾使用过一两次 Get-Command 或其简单的别名 (gcm) 来查看可用的 Windows PowerShell cmdlet 的列表。但是,您可能不知道 gcm 有多么灵活。例如,如果要查看 Windows PowerShell 可对一项服务执行的所有操作,请运行 gcm -noun service。或者,如果要查看所有的 Windows PowerShell 导出选项,请尝试 gcm -verb export。如果只需查看由特殊管理单元(如 PowerShell Community Extensions)添加的 cmdlet,请尝试 gcm -pssnapin pscx。(用任何管理单元的名称替换“pscx”,即可查看该管理单元的 cmdlet。)

您可以看到,Get-Command 在 Windows PowerShell 的识别能力中发挥着重要作用。通过此命令,您无需参考手册即可了解哪些功能是可用的。另请注意,与使用 Help * 等命令相比,gcm 能够更精确地发现功能。Help 功能仅列出可用的帮助主题。帮助中未附带的任一 cmdlet 都不会显示在帮助列表中 — 但在需要时您可以调用这些 cmdlet。

这种方法的优点远不止是生成规范的表。只要您使用对象,Windows PowerShell 就可以帮助您做很多事情。要将您的数据放在 CSV 文件中?使用 Export-CSV。喜欢使用 HTML 表?将对象以管道形式传送到 ConvertTo-HTML 中。需要列表格式?以管道形式将其传送到 Format-List。通过使用对象,您可以利用 shell 已提供的所有功能。以下是修改后的示例:

functionStringVersions {
  PROCESS {
   $obj = New-Object PSObject
   $obj | Add-Member NoteProperty Original($_)
   $obj | Add-Member NoteProperty Uppercase($_.ToUpper())
   $obj | Add-Member NoteProperty Lowercase($_.ToLower())
   Write-Output $obj
}
}

这次,我修改了函数以接受管道输入(使用对象时最好这样做)并输出到管道中。

现在,该函数在 PROCESS 脚本块内部有自己的代码。这意味着函数将接受管道输入,并为管道送入的每个对象执行一次 PROCESS 脚本块。

在 PROCESS 脚本块中,特殊的 $_ 变量引用当前处理的管道对象。这样的实际结果是现在可以直接传送一个字符串数组:

@("one","two","three") | StringVersions

因为此函数将其输出放到管道中,所以我获得了一个表。在管道的末尾,shell 知道调用其格式化子系统,该子系统决定使用一个表,因为管道中对象的属性少于五个(默认情况下,如果有更多属性,shell 将使用列表)。

但是我不必依靠默认行为。我可以直接将这些对象传送到另一个 cmdlet 以便同时完成一些其他操作:

@("one","two","three") | StringVersions | Format-List
@("one","two","three") | StringVersions | ConvertTo-HTML | Out-File "strings.html"
@("one","two","three") | StringVersions | Export-CSV "strings.csv"
@("one","two","three") | StringVersions | Select Uppercase,Lowercase -unique

图 2 显示了 Web 浏览器中显示的第二个示例的结果 HTML。通过直接在对象中表示输出数据,而不是将其作为简单文本表示,即可完全访问 shell 中内置的丰富功能:各种格式化布局、HTML 转换、导出选项,以及排序、筛选和组合等。

图 2 HTML 格式的 Windows PowerShell 数据输出

图 2** HTML 格式的 Windows PowerShell 数据输出 **(单击该图像获得较大视图)

这是功能非常强大的素材。实际上,我甚至建议您写的每个脚本都应该产生对象作为它的输出,这样一来,您就可以用尽可能多的方法来利用该输出 — 而根本不必再写一行代码。

Don Jones 是 Windows 管理自动化的专家并已著有*《Windows PowerShell:TFM》《VBScript, WMI, and ADSI Unleashed》*等书籍。您可以通过 ScriptingAnswers.com 论坛与他联系。

© 2008 Microsoft Corporation 和 CMP Media, LLC。保留所有权利;未经允许不得复制本文的部分或全部内容.