第14章 Windows管理规范
我们一直期望但是又害怕写这一章。Windows管理规范(Windows Management Instrumentation,WMI)可能是微软提供给管理员使用最优秀的工具之一。但同时它也是这个公司曾经给我们造成最多问题的部分。WMI可以从计算机中收集大量系统信息。但有时候这些信息不易看懂,另外文档也不够友好。在本章,我们将从PowerShell的角度介绍WMI,以及WMI的工作方式和一些不完美的地方,以便全面揭示你将会遇到的问题。
需要强调的是,WMI是一个外部技术;PowerShell仅仅与其接口交互而已。本章的重点将放在PowerShell如何与WMI交互,而不是WMI的底层实现机制。
14.1 WMI概要
典型的Windows计算机包含数万个管理信息,WMI会将这些信息整理成易于访问的形式。
在最顶层,WMI被组织成命名空间(namespace)。可以把命名空间想象为关联到特定产品或技术的一个文件夹。比如,“root\CIMv2”,该命名空间包含了所有Windows操作系统和计算机硬件信息。而“root\MicrosoftDNS”命名空间包含了所有关于DNS服务器的信息。在客户端计算机上,“root\SecurityCenter”包含了关于防火墙、杀毒软件和反流氓软件等工具的信息。
在命名空间中,WMI被分成一系列的类,每个类都是可用于WMI查询的管理单元。比如,在“root\SecurityCenter”中的“Antivirus-Product”类被设计用于保存反间谍软件的信息;在“root\CIMv2”中的“Win32_LogicalDisk”类被设计用于保存逻辑磁盘的信息。但是即使一个计算机上存在某个类,也不代表计算机上实际安装了对应组件。比如无论是否安装了磁带驱动程序。“Win32_TapeDrive”类在所有的Windows版本上都存在。
当你有一个或多个可管理组件时,你可以看到在对应的类中有相同数量的实例(instances)。一个实例由类代表了一个现实世界的事件。如果你的计算机只有一个单一的BIOS,那么在“root\CIMv2”中会有一个关于“Win32_BIOS”的实例。如果计算机安装了100个后台服务,你会看到100个“Win32_Service”的实例。请注意,在“root\CIMv2”中的类型一般以“Win32_”可“CIM_”开头。
14.3 探索WMI
最佳的WMI入门恐怕是暂时抛开PowerShell并从WMI自身出发。这里我们使用WMI探索工具。不幸的是,这些工具就像季节更替那样经常更换,所以我们犹豫是否该告诉你某个特定工具。你可以尝试在搜索引擎中搜索WMI explorer并查看结果。你也可以尝试访问 http://powershell.org/wp/2013/03/08/wmi-explorer/。我们可以从这类工具中得到大部分所需的关于WMI的信息。当然,这个工作要求耐心和不少的浏览量——这并不是最佳方法,但是我们最终还是选择了这个工具。
由于每台计算机上的WMI命名空间和类都不尽相同,所以你需要把工具直接在准备查询的机器上运行,以便看到对应机器的WMI仓库。
另一个途径是使用PowerShell本身。比如,我们想知道一些关于磁盘的信息。可以尝试下面的命令。
Get-WmiObject -Namespace root\CIMv2 -list | where name -like '*dis*'
14.4 选择你的武器:WMI或CIM
在PowerShell v3及后续版本中,有两种与WMI交互的方式。
- 所谓的“WMI Cmdlets”,例如“Get-WmiObject”与“Invoke-WmiMethod”——这些都是遗留命令,意味着它们依旧能工作,但是微软不会对他们进行后续开发投入。它们与远程过程调用(RPC)交互,也就是说,只有在防火墙支持状态审查时才能通过防火墙(实际上很难)。
- 新版的“CIM Cmdlets”,例如“Get-CimInstance”与“Invoke-CimMethod”——它们或多或少等价于旧版本的“WMI Cmdlets”,但是它们通过WS-MAN交互,替代原有的RPCs。这是微软的主方向,执行“Get-Command -noun CIM*”可以显示很多微软提供的这类命令的功能。
毫无疑问,这些命令的后端同样是WMI,其差异在于如何交互和如何被使用。
14.5 使用Get-WmiObject
通过“Get-WmiObject”命令,你可以指定一个命名空间、一个类名称甚至远程计算机的名称以及备用凭据名。如果需要,还可以从指定的计算机中查询该类的所有实例。
如果要减少类实例的返回结果,甚至可以提供筛选条件实现,可以使用下面的语法获取一个命名空间中的类列表。
Get-WmiObject -namespace root\cimv2 -list
注意,命名空间名字使用的是反斜杠,不是斜杠。
也可以通过指定命名空间和类型查询一个类。
Get-WmiObject -namespace root\cimv2 -class win32_desktop
其中“root\CIMv2”是Windows XP SP2及后续版本的系统默认命名空间,所以如果你的类在该命名空间中,可以不显式指定。同时,“-Class”是位置参数,也就是说,如果你把类名称放到第一个位置,它依旧能正常工作。
这里有两个例子,其中一个使用Gwmi别名代替完整的Cmdlet名称。
PS C:\>Get-WmiObject win32_desktop
PS C:\>gwmi antispywareproduct -namespace root\securitycenter2
对于许多WMI类,PowerShell的默认配置已经设定了需要展示的属性。“Win32_OperatingSystem”是一个很好的例子,因为它默认仅在列表中展示了6个属性。请记住,你总能把WMI对象用管道传输到“Gm”或“Format-List”中,以便查看所有可用的属性。“Gm”问题列出所有可用的方法。下面是一个示例。
PS C:\>Get-WmiObject win32_operatingsystem | gm
另外,“filter"参数允许你通过指定的规则查询特定实例。该参数使用越来有点棘手。下面的示例可以看出其最坏情况下的结果。
PS C:\>gwmi -class win32_desktop -filter "name='COMPANY\\ADMINISTRATOR'"
对于该命令的输出结果,需要注意下面事项。
- 筛选条件通常被双引号包住。
- 筛选比较操作符并不使用PowerShell的常规操作符“-eq”或“-like”,而使用更加传统、更加编程化的操作符,比如=、>、<、<=、>=和<>。可以使用关键字“LIKE”作为操作符,但在匹配值时必须使用“%”作为字符通配符,如“NAME LIKE '%ADMINISTRATOR%'”。注意,这里不能像PowerShell的其他地方一样使用*作为通配符。
- 字符串匹配是以单引号包住,这也是筛选表达式的最外层的引号是双引号的原因。
- 避免在WMI中使用反斜杠。当你需要使用文本的反斜杠时,你必须使用两个反斜杠替代。
- Gwmi的输出结果总会包含大量的系统属性。PowerShell的默认显示配置通常会隐藏这些属性,如果你故意列出的这些值或类没有默认配置,那么这些值会被显示出来。系统属性名称以双下划线开始。这里有两个非常有用的属性。
- __ SERVER:包含被查询实例所在的计算机名称。当所查询的WMI信息来自多台计算机时非常有用,该属性与易于记忆的“PSComputerName”属性功能一致。
- __PATH:是实例本身的绝对引用。如果需要的话,可以用来查询实例。
该Cmdlet不仅可以从远程计算机中查询信息,也可以从多台计算机中检索,可以使用任何可以生成一个包含计算机名称或IP列表的技术。
PS C:\>Gwmi Win32_BIOS -Comp server-r2,server3,dc4
一旦你查询到一个WMI实例的集合后,就可以把它们用管道连接到任何以“-Object”cmdlet、“Format-”Cmdlet或“Out-”“Export-”“ConverTo-”开头的Cmdlet中。你可以使用自定义表格显示“Win32_BIOS”类的信息。
PS C:\>Gwmi Win32_BIOS | Format-table serialNumber,Version auto
在第10章中,我们已经介绍了如何使用“Format-Table”Cmdlet生成定制列。当你想从一台给定计算机中查询一些WMI类并集成到一个表时,该技术在这里就可以派上用场。此时你可以创建一个关于表的自定义列,并用列的表达式执行一个全新的WMI查询。语法如下,虽然看上去有点头大,但是结果却能让人满意。
PS C:\>gwmi -class win32_bios -computer server2,localhost |
format-table @{label='ComputerName';expression={$_.__SERVER}},
@{label='BIOSSerial';expression={$_.SerialNumber}},
@{label='OSBuild';expression={gwmi -class win32_operatingsystem -computer $_.__SERVER | select-object -expand BuildNumber}} -autosize
14.6 使用Get-CimInstance
Get-CimInstance是PowerShell v3引入的新命令,与“Get-WimObject”有很多相似的地方,但是也有几个语法上的差异。
- 你需要使用“-ClassName代替“-Class”(虽然你只需要输入-Class,但是如果你记住了该参数名称的话,这没有问题)。
- 没有用于列出命名空间中的所有类的“-List”参数。而是使用“Get-Ciminstance”并搭配“-namespace"参数获取列表。
- 没有“-Credential”参数;如果你需要从远程计算机查询并被要求提供替代凭据,需要通过“Invoke-Command”发送“Get-Ciminstance”。
比如:
PS C:\>Get-Ciminstance -ClassName Win32_LogicalDisk
如果你需要使用替代凭据查询远程计算机,可以使用类似下面的命令。
PS C:\>invoke-command -scriptBlock {Get-CimInstance -ClassName win32_process } -ComputerName win8 -Credential DOMAIN\Administrator