Windows PowerShell数据的筛选与格式化

Don Jones

毫无疑问,Windows PowerShell 在您勿需进行大量的工作的情况下,就可以返回许多宝贵的信息。以简单的 Get-WMIObject cmdlet 为例,它可以用来返回本地计算机上的服务列表。默认视图列出了所运行服务的状态、名称和启动模式,

其实质上是一种“服务”控制台的命令行视图。Windows PowerShell™ 能使其更加容易实现。

不过,还可以为服务提供大量更加有用的信息,而不仅仅是在默认视图中显示出来的部分。试试运行这个命令:

$s = get-wmiobject win32_service
$s[0] | gm

第一行命令返回所有服务的集合(或者,更确切地说是来自 Windows® Management Instrumentation 或 WMI 的 Win32_Service 类的所有实例),并将其存储在变量 $s 中。第二行命令调用此集合中的第一个服务(在方括号中指明的序号零),并将其传送到 Get-Member cmdlet(在此使用它的别名,gm)。输出结果显示此数据类型所有可用的属性和方法。我决定使用 WMI 的 Win32_Service 类,而不用 Windows PowerShell 内置的 Get-Service cmdlet,因为与 Microsoft® .NET Service­Controller 对象相比,WMI 实际上能够提供更多的信息,其中包括 Start­Name 属性。该属性可告诉我在其下运行服务的用户账户的名称。您可以使用如下方法检查单个实例(如第一个)的名称:

PS C:\> $s[0].StartName
LocalSystem

然而,这些服务并没有任何特定的排列顺序,所以用集合中的序号来引用服务效果不是很好。(其通常以字母顺序排列,但并非始终如此。)从管理的角度来讲,或许您最感兴趣的是全部服务的列表和每个用来登陆的账户。这样对于某些方面有相当的便利性,比如说遵从性审核。那么让我们稍作停留,来看一看 WMI 的默认设置。我将使用 Get-WMIObject 的缩写,gwmi(见图 1)。

Figure 1 使用 gwmi

PS C:\> gwmi win32_service

ExitCode  : 0
Name      : AcrSch2Svc
ProcessId : 1712
StartMode : Auto
State     : Running
Status    : OK

ExitCode  : 1077
Name      : Adobe LM Service
ProcessId : 0
StartMode : Manual
State     : Stopped
Status    : OK

显然这仅是一个示例,但是您可以看到输出结果并不太适用于管理报告。我想知道的是服务的名称和 StartName(即服务在其下运行的账户)。我也希望报告的格式可读性更强,而不是这种感觉有点笨笨的列表。这就是 Windows PowerShell 中具备强大格式化和数据筛选功能的 cmdlet 发挥作用的地方。

获取您所需要的数据

我将从 Get-WMIObject 筛选数据作为开始,因此现在显示的消息就是我感兴趣的属性。最佳的实现方式是使用 Windows PowerShell Select-Object cmdlet,其简写的别名为 select。Select 用于接收对象的集合(诸如由 Get-WMIObject 所返回的集合),并显示这些对象所需要的属性。这意味着我可以将 gwmi 的输出传送到 select,并指定我所感兴趣的两种属性。图 2 显示了结果,其中包含了用表格形式所显示的 Name 和 StartName 属性。

图 2 仅查看表格中的 Name 和 StartName 属性

图 2** 仅查看表格中的 Name 和 StartName 属性 **(单击该图像获得较大视图)

假设我是为遵从性审核目的而生成此报告,那么其中包含的信息确实多了些。由于某些服务已被禁用,因此任何读取禁用服务理论上会使用哪些账户相关的输出结果,均无实际意义。因而,我会筛选掉所有具备“禁用”启动类型的服务,也就是 Win32_Service 类的 StartMode属性。

Windows PowerShell 使用 Where-Object cmdlet(其缩写为 where)来筛选对象。where cmdlet 接收输入对象的集合并通过脚本块逐一运行,基于一套定义好的标准来决定是否每个对象都将在 cmdlet 的输出中显示。每个符合标准的对象生成的比较结果为 True,并包含在输出结果中;而产生 False 值的对象不会包含在内。

因此,我决定只需要那些 StartMode 属性设为禁用的对象。在 Windows PowerShell 内容中,该评估是这样的:

$object.StartMode –eq “Disabled”

当然,$object 仅仅是一个例子。事实上我并没有在编写脚本,而且我没有命名为 $object 的变量。在 where 使用的脚本块中,我却有一个特殊的名为 $_ 的变量,它代表当前正在被 cmdlet 评估的对象。因此我的 where 脚本块可能是这样的:

$_.StartMode –eq “Disabled”

我可以很轻松地对其进行测试:

PS C:\> gwmi win32_service | where 
{$_.StartMode -eq “Disabled”}

ExitCode  : 1077
Name      : Alerter
ProcessId : 0
StartMode : Disabled
State     : Stopped
Status    : OK

当然,在此快速测试中,输出结果会以默认的列表样式返回显示。同时,为了节约空间,在此仅包含了一个服务。但您会注意到此输出是反向的。我已包含了禁用服务在内,而非将它们排除在外。这是因为得让我的脚本块反向:我需要包括所有 StartMode 属性不是禁用的服务,正如对我的示例进行修改后那样:

PS C:\> gwmi win32_service | where 
{$_.StartMode -ne “Disabled”}

ExitCode  : 0
Name      : AcrSch2Svc
ProcessId : 1712
StartMode : Auto
State     : Running
Status    : OK

这样更好!现在输出结果中仅包含我真正感兴趣的服务,我能够再一次将结果传送到 select 并指定我需要的属性:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | select name,startname

将数据从一个 cmdlet 传送到另一个再到另一个 cmdlet 的过程,真正说明了 Windows PowerShell 的功能。我依然没有编写脚本,但是我却实现了从大量数据集中筛选出我所需要的输出结果这一目的。

合适的外观

您应该注意,select 的输出仍然只是一组对象。当我使用 Windows PowerShell 检索格式美观的表格时,正是 PowerShell.exe 在对这些对象进行编译。换句话说,Windows PowerShell 知道我作为一个普通人不可能看见这些对象,因此它采用文本的形式来呈现这些对象。在这种情况下,对象以表格的形式呈现,同时每个属性都有相应的一列予以对应,如图 2 所示。

看起来这样对于审核目的已经足够了。但我想再说一遍,也许不是。不同的人有不同的需求,Windows PowerShell 并不会假设您的特定需求。相反,它为您提供最好的工具来格式化输出。四个内置的 cmdlets - Format-List、Format-Custom、Format-Table 和 Format-Wide - 用来接收对象的集合(比如由 select 返回的集合),并用不同的方式格式化这些对象。Windows PowerShell 基本上使用 Format-Table 来格式化 select cmdlet 的输出结果。想看看不同的外观,可以试一下 Format-List:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | format-list

结果有点像这个示例:

name      : AcrSch2Svc
startname : LocalSystem

name      : Adobe LM Service
startname : LocalSystem

Format-Wide cmdlet 会生成一个多栏的列表,默认情况下为每个对象的第一个属性。以下面这一行为例:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} |
 select name,startname | format-wide

它生成一张服务名称列表,但这并不是我想要的。输出中没有 StartName(见图 3),而在审核报告中,StartName 是我所需要的一条重要信息。

图 3 Format-Wide cmdlet 显示的输出结果中省略了关键信息 -- StartName

图 3** Format-Wide cmdlet 显示的输出结果中省略了关键信息 -- StartName **(单击该图像获得较大视图)

因为我仅需处理两种属性,所以 Format-Table 或 Format-List 看起来都是可以接受的。但是审核人员看到屏幕上的上述信息可能不会感到高兴。她可能更喜欢某种格式的文件。

导出数据

那么,审计人员希望如何查看数据呢?输出服务列表并登录到 CSV(逗号分割值)文件可能就足够了,因为可用 Microsoft Excel® 很方便的打开该文件。要创建一个 CSV 文件,只需将您的输出传送到 Windows PowerShell Export-CSV cmdlet:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | export-csv c:\services.csv

当然,在当今社会,CSV 似乎有一点过时。 或许审计人员会更希望数据以网页的形式显示到 Intranet 服务器上。 为了做到这一点,需要使用 ConvertTo-HTML cmdlet 将输出转换成 HTML:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | convertto-html

原始的 HTML 难以查看,因此您需要将输出结果写到一个文件中:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | convertto-html | out-file c:\services.html

图 4 显示的结果是一种格式美观的 HTML 页面,可以发布到任何 Web 服务器上,而不需要做进一步的修改。

图 4 用格式美观的 HTML 页面显示输出结果

图 4** 用格式美观的 HTML 页面显示输出结果 **(单击该图像获得较大视图)

相关事实

Windows PowerShell 为您提供访问大量管理数据的快速途径。然而,从业务的角度来说,这些数据在原始状态下并不是始终都有用的。

通过筛选数据(使用 where )、选择所需要的对象属性(使用 select )以及应用相应的格式化选项(比如 Format-Table 或 Format-List),您可以轻松快捷地将管理数据转换为有用的信息。然后,通过将数据导出为一种易于共享的文件格式,您可以将该信息进行共享并与组织内其他同事交流宝贵的信息。

Don Jones 是 SAPIEN Technologies 的项目和服务主管,也是Windows PowerShell:TFM (SAPIEN Press) 的合著者。通过网站联系 Don,网址是 www.ScriptingAnswers.com

© 2008 Microsoft Corporation 与 CMP Media, LLC.保留所有权利;不得对全文或部分内容进行复制.