PowerShell WMI: 自动化 Windows 任务

Windows管理仪表板(WMI)在Windows中已经存在很长时间了。许多IT专业人员直接使用了WMI,或者使用了从WMI读取信息的工具。您知道PowerShell WMI cmdlet是内置的吗?

WMI是收集关于Windows机器信息和在Windows内部操作各种服务的事实标准地点。由于WMI提供了大量信息,您可以利用PowerShell WMI进行访问。使用PowerShell查询WMI允许您在Windows计算机上自动执行数千个任务。

幸运的是,PowerShell最早支持的系统之一是WMI。由于您拥有本机的PowerShell WMI cmdlet,这意味着IT管理员可以利用PowerShell易于理解的动词/名词语法与WMI进行交互,正如您将看到的,高级用户也可以通过使用标准的PowerShell命令直接调用WMI事件和类。

PowerShell WMI Cmdlet与CIM的对比

在使用PowerShell中的WMI时有两种“集”命令。一些人将这些“集”称为与WMI交互的“旧”方法和CIM cmdlet。从WMI查询信息时,两者都返回相同的信息,但处理方式略有不同。从WMI读取信息的“旧”方法是使用Get-WmiObject命令。其他WMI cmdlet包括Invoke-WmiMethodRegister-WMIEvent等等,但我们在本文中将不涉及这些。

PowerShell WMI cmdlet Get-WmiObject 有效,但存在一个严重缺陷。在查询远程计算机时,它依赖于DCOM,而DCOM在历史上一直是恶意攻击者的攻击向量。DCOM通常会被各种防火墙阻止。由于这是“旧”方法,我们不打算深入介绍这种方法。相反,我们将专注于CIM cmdlets:主要是Get-CimInstance

DCOM Component Services

Get-WmiObjectGet-CimInstance 之间的主要区别在于,Get-CimInstance 不是使用DCOM访问远程计算机,而是使用WSMAN协议,该协议是熟悉的PowerShell远程功能的传输。

PowerShell CIM Cmdlets

假设您想返回有关远程计算机上Windows版本的一些信息。在这种情况下,我想要从名为DC的计算机中获取一些信息。您可以通过指定包含信息的WMI类以及我想要查询的计算机名称来执行此操作。

您可以看到下面的示例中,由于Get-CimInstance 默认情况下不显示类中的所有属性,因此我必须将输出导入到Select-Object 命令中以返回所有属性。

PS> Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName DC | Select *
Status                                    : OK
Name                                      : Microsoft Windows 10 Pro|C:\WINDOWS|\Device\Harddisk0\Partition2
FreePhysicalMemory                        : 1802336
FreeSpaceInPagingFiles                    : 800308
FreeVirtualMemory                         : 1472916
Caption                                   : Microsoft Windows 2016
Description                               :
InstallDate                               : 7/5/2018 6:04:09 PM
CreationClassName                         : Win32_OperatingSystem
CSCreationClassName                       : Win32_ComputerSystem
--snip-

不仅可以通过属性收集信息,还可以在类上调用WMI/CIM方法。这方面的一个很好的例子是在远程计算机上停止进程。本地情况下,通过PowerShell中的Stop-Process命令无法做到这一点。然而,通过WMI查询是一种方法。要终止远程进程,首先需要找出要终止的进程。可以通过查看Win32_Process类来枚举远程计算机上的所有运行进程。

PS> Get-CimInstance -ClassName CIM_Process -ComputerName DC

ProcessId Name                                      HandleCount WorkingSetSize VirtualSize   PSComputerName
--------- ----                                      ----------- -------------- -----------   --------------
0         System Idle Process                       0           4096           65536         DC
4         System                                    631         212992         3465216       DC
232       smss.exe                                  52          823296         4325376       DC
328       csrss.exe                                 258   om      3346432        49483776      DC
392       csrss.exe                                 87          2789376        44507136      DC
400       wininit.exe                               80          3072000        2199065096192 DC
428       winlogon.exe                              119         4431872        2199079510016 DC

一旦确定了要终止的进程,然后可以将其名称传递给Win32_Process类上的Terminate()方法。为此,需要捕获要终止的进程的实例。

请注意,下面我使用Filter参数确保只接收ccmexec.exe进程。这很重要!

一旦捕获了实例,就可以使用Invoke-CimMethod命令调用Terminate()方法来终止进程,如下所示。

PS> $instance = Get-CimInstance -ClassName CIM_Process -ComputerName DC -Filter 'Name = "ccmexec.exe"'
PS> $instance

ProcessId Name        HandleCount WorkingSetSize VirtualSize PSComputerName
--------- ----        ----------- -------------- ----------- --------------
3528      CcmExec.exe 878         34246656       158261248   DC


PS> Invoke-CimMethod -InputObject $instance -MethodName Terminate

ReturnValue PSComputerName
----------- --------------
          0 DC

摘要

如果您想了解有关在PowerShell中使用WMI的更多信息,特别是使用未在此处介绍的PowerShell WMI cmdlet Get-WmiObject的信息,我鼓励您查看Get-WmiObject:查询本地和远程计算机上的WMI,在那里我深入探讨了WMI并使用了Get-WmiObject cmdlet。

对于所有 CIM cmdlet 的详细介绍以及它们在 PowerShell 中的工作方式,请参阅 Technet 上的 Introduction to CIM Cmdlets 文章。在那里,您将看到所有不同的 CIM cmdlet,以及它们在脚本中的可能用法。

Source:
https://adamtheautomator.com/powershell-wmi/