- WMI 和 PowerShell 的 CIM cmdlet 可以让你高效地查询和修改本地和远程管理信息。
- 使用 WSMan 或 DCOM 的 CimSession 可以安全兼容地访问现代和传统网络设备。
- 高级函数、模块、作业和 DSC 的使用使 PowerShell 成为一种完整的基础架构自动化语言。
- PowerShell 将本地、远程、Azure 和 Microsoft 365 管理集成到一个环境中,从而减少了重复的手动任务。

如果你从事 Windows 系统管理工作,迟早会接触到PowerShell、WMI 和高级自动化。这不仅仅是知道如何运行几个命令的问题:当你管理几十台甚至几百台服务器时,你需要一种严谨、结构化且安全的方法来收集信息、应用更改和重复执行任务,而不会崩溃……或者破坏任何东西。
接下来,我们将以冷静而全面的方式探讨如何利用WMI、CIM 和 PowerShell 远程通信来实现从简单查询到复杂基础架构场景的自动化。我们还将了解所有这些如何与模块、后台任务、Azure、Microsoft 365 以及一些能够真正提升系统管理员日常工作的高级功能相结合。
PowerShell 增强功能和高级自动化概述
Windows PowerShell 自早期版本以来已经有了很大的发展,其中很大一部分发展来自于 Windows Server 2012,该版本改进了远程通信,扩展了可用的 cmdlet,并且使调试、后台作业和受限端点等功能更容易使用,从而提高了安全性。
该环境的核心理念之一是,管理员无需编写大量代码即可创建类似 cmdlet 的行为,这得益于其高级功能、可重用模块和全面的帮助系统。这意味着,您无需依赖分散的图形工具,即可构建一套连贯的脚本和模块,从而自动执行服务器、网络、Active Directory、Azure 或 Microsoft 365 的管理流程。
在高级自动化领域,诸如异步执行任务的作业、工作流、基于配置的 PowerShell DSC 管理以及 JEA(Just Enough Administration,恰好足够管理)或 PowerShell Web Access 等安全选项等功能也十分突出,从而可以详细控制每个人可以做什么以及从哪里可以做。
整个生态系统与 WMI 和 CIM 特别契合,因为操作系统公开的管理信息(硬件、服务、进程、网络配置、已安装的软件等)变成了一组对象,您可以使用专为批量自动化设计的 PowerShell 命令来查询、筛选和修改这些对象。
WMI 和 CIM:关键概念和实际区别
Windows 管理规范(Windows Management Instrumentation,简称WMI)是一种独立于 PowerShell 的技术,多年来一直是 Windows 系统的一部分。它公开了一个包含操作系统、硬件和许多应用程序管理信息的存储库。虽然 WMI 本身并不依赖于 PowerShell,但 PowerShell 却广泛利用 WMI 来实现任务自动化。
PowerShell 生态系统中 WMI 的自然继承者是CIM(通用信息模型)cmdlet,它是在 PowerShell 3.0 中引入的。这些 cmdlet 被分组在 CimCmdlets 模块中,其中包括 Get-CimInstance、Get-CimClass、New-CimInstance、Invoke-CimMethod、Register-CimIndicationEvent、Set-CimInstance 和 Remove-CimInstance 等命令。
在旧版本的 Windows PowerShell 中,例如 Windows 10 PowerShell 5.1 或 Windows 11 PowerShell,您仍然可以找到经典的 WMI cmdlet(Get-WmiObject、Invoke-WmiMethod、Register-WmiEvent、Remove-WmiObject 和 Set-WmiInstance)。但是,这些 cmdlet 已被弃用,不再包含在 PowerShell 6 及更高版本中,因此它们仅对维护旧脚本或审查旧代码有用。
当有人谈到“使用 CIM cmdlet 查询 WMI”时,这并不矛盾:CIM cmdlet 仍然可以访问 WMI 信息,但它们使用的是更现代的协议(例如 WSMan)和更一致的 API。实际上,对于新开发项目,您应该专注于 CIM,只有在需要迁移或理解旧脚本时才考虑使用 WMI cmdlet。
过去,许多管理员使用 VBScript 和 WQL 查询语言来查询 WMI,例如,连接到root\CIMV2命名空间并查询 Win32_BIOS 等类。如今,只需传递 -Query 参数,即可使用 Get-CimInstance 重用相同的 WQL 查询,这大大简化了从 VBScript 到 PowerShell 的过渡,而无需从头开始重写逻辑。
Get-CimInstance 的实际应用和高效查询
对于日常工作,使用 PowerShell 查询 WMI 最自然的方式是使用带有 -ClassName 参数的 Get-CimInstance 命令,而不是编写完整的 WQL 查询。例如,要获取 BIOS 信息,可以使用 Get-CimInstance -ClassName Win32_BIOS,即可获得一个包含 Manufacturer、Name、SerialNumber 或 SMBIOSBIOSVersion 等属性的对象。
由于 PowerShell 中一切皆对象,因此很容易筛选并选择所需内容。如果您只对序列号感兴趣,可以将结果通过管道传递给 `Select-Object -Property SerialNumber`,或者使用 `Select-Object -ExpandProperty SerialNumber` 输出一个简单的字符串,而不是包含该属性的对象。另一种常用的方法是使用点语法(`Get-CimInstance ...`).SerialNumber`)直接访问该值。
值得注意的是,默认情况下,WMI 查询返回的属性数量会比实际需要的要多。在本地计算机上,这通常没什么问题,但当需要查询大量远程计算机时,就会增加处理时间和不必要的网络流量。这时,`Get-CimInstance` 命令的 `-Property` 参数就派上了用场,它允许您限制从源检索哪些属性。
例如,通过指定 `-Property SerialNumber` 参数,可以减少数据传输量,从而加快查询速度,提高查询效率,尤其是在大规模应用时。这种“只请求所需数据”的理念在设计运行于数十台甚至数百台机器上的库存或审计脚本时至关重要。
总而言之,无论您是处理具体类、旧版 WQL 查询,还是要优化检索的特定属性, Get-CimInstance 都能在简单性(一条命令行)和灵活性之间取得强大的平衡。
使用 CIM、会话和 WSMan/DCOM 协议进行远程咨询
当你离开本地计算机并开始访问远程计算机时,权限、通信协议和性能等多个因素都会影响结果。虽然许多人认为 PowerShell “危险”,但事实是它并不会赋予你任何额外的权限:你拥有的权限与使用图形界面或其他任何工具时完全相同,不多也不少。
如果您尝试在权限不足的情况下运行 `Get-CimInstance -ComputerName Server -ClassName Win32_BIOS` 命令,将会收到“拒绝访问”错误。这并非 PowerShell 本身出现故障,而是因为您当前运行会话的用户没有访问 WMI 中该信息的权限。当然,您可以以域管理员身份打开控制台,但这会导致所有命令都以该权限执行,这在许多环境中都是不必要的风险。
建议遵循最小权限原则,仅在必要时提升权限。在支持 `-Credential` 参数的 cmdlet 中,您可以仅为相关命令指定备用凭据。然而,`Get-CimInstance` 并不直接接受 `-Credential` 参数,而 `CimSessions` 则提供了一个优雅的解决方案。
CimSession 是与远程计算机建立的持久连接,您可以使用 `New-CimSession` 命令创建该连接,并传递计算机名称和凭据(例如,`New-CimSession -ComputerName dc01 -Credential (Get-Credential)`)。此会话存储在一个变量中,例如`$CimSession`,然后可以通过使用 `Get-CimInstance` 命令的 `-CimSession` 参数而不是 `-ComputerName` 参数来重用该会话,从而允许您将多个查询合并到单个连接中。
除了凭据要求外,Get-CimInstance 默认使用WSMan 协议(基于 WinRM)。这意味着远程计算机必须具有 WSMan 堆栈版本 3.0 或更高版本,通常 PowerShell 3.0 及更高版本都包含此版本。您可以使用 `Test-WSMan -ComputerName RemoteComputer` 命令检查计算机上的 WSMan 堆栈版本,并验证“Stack”值是否为 3.0 或更高才能使用此连接方法。
CIM 会话与 DCOM 和向后兼容性
基于 Get-WmiObject 的旧版 WMI cmdlet 依赖于DCOM 协议,而旧版 Windows 仍然支持该协议。问题在于,在较新的系统中,防火墙通常默认阻止 DCOM,因此需要手动打开特定端口才能正常使用,这可能会违反组织的安全策略。
CIM cmdlet 提供了一种强大的折衷方案:您可以使用`New-CimSessionOption -Protocol Dcom`创建会话选项,将其保存到变量(例如 `$DCOM`)中,然后使用 `New-CimSession` 将它们组合起来,生成一个使用 DCOM 而不是 WSMan 的 CimSession。这使您可以连接到非常老旧的服务器,甚至是早于 Windows Server 2000 的服务器,这些服务器甚至没有安装 PowerShell。
通常情况下,将域管理员凭据或提升权限帐户的凭据存储在变量中(例如,`$Cred = Get-Credential`)会很方便,这样就无需每次都输入。然后,使用类似 `New-CimSession -ComputerName sql03 -SessionOption $DCOM -Credential $Cred` 的命令,可以通过 DCOM 启动与不支持 WSMan 但支持 WMI 的旧服务器之间的 CimSession。
从脚本编写者的角度来看,主要优势在于`Get-CimInstance` 的输出不会因协议而异:无论使用 WSMan 还是 DCOM,都能获得相同的对象和属性。这大大简化了逻辑,因为可以将对相应协议的检测封装在一个函数中,让其余代码始终透明地处理 CimSession。
事实上,创建自定义函数来测试 WSMan(使用 Test-WSMan),并在 WSMan 不可用时自动使用 New-CimSessionOption 切换到 DCOM,这种做法非常常见。这样,您就可以在包含现代服务器和传统服务器的混合环境中标准化 CimSession 的创建,而无需在所有脚本中重复编写连接逻辑。
CimSessions 的管理、列表和清理
当您开始大量使用 CimSession 时,务必跟踪它们,以避免建立不必要的连接。使用Get-CimSession 命令,您可以列出所有打开的会话,查看它们指向的计算机,以及它们使用的协议(WSMAN 或 DCOM),这对于诊断连接或身份验证问题非常有用。
您还可以将这些现有会话检索到一个变量中,例如$CimSession = Get-CimSession,并在单个命令 Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS 中使用这些会话,以便一次查询多台计算机,并将 WSMan 和 DCOM 会话合并到同一操作中。
分析完这些信息后,最好关闭会话,以免不必要的资源占用。Get -CimSession | Remove-CimSession cmdlet可以一次性从当前配置文件中删除所有活动的 CimSession。或者,您也可以将特定会话传递给 Remove-CimSession cmdlet,以便仅关闭其中的一部分。
这种方式可以让你控制连接和断开连接的周期,强烈建议在计划任务、自动化运行手册或持续集成管道中使用脚本,因为如果不明确规划清理工作,可能会导致会话挂起。
PowerShell 作为一种全面的自动化语言
除了 WMI 和 CIM 之外,PowerShell 已发展成为一种通用的自动化语言,其功能远远超出了典型的 Windows 管理脚本。市面上有很多书籍和课程专门介绍其高级功能,涵盖了从在 Linux 和 Windows 上安装 PowerShell,到通过 NuGet 开发可分发模块,甚至包括 Visual Studio Code 等现代开发环境等方方面面。
通常,入门的关键在于深入理解PowerShell 的高级功能,这些功能允许您定义参数、执行验证、生成结构化输出,并像使用原生 cmdlet 一样访问集成帮助。在此基础上,将代码组织成模块有助于运维团队的协作,因为您可以对这些模块进行版本控制,并将其发布到内部或公共的基于 NuGet 的存储库中。
使用自定义对象和类也至关重要,这为构建比传统线性脚本更丰富的数据模型打开了大门。这使您可以封装业务逻辑、重用结构,并为您的管理团队设计内部 API,所有这些都由 PowerShell 引擎提供支持。
在高级自动化领域,后台作业和工作流发挥着至关重要的作用,它们能够管理异步任务、在不阻塞控制台的情况下执行耗时较长的操作,以及协调跨多台机器的复杂序列。这些功能非常适合对 WMI/CIM 进行批量查询和远程管理场景,在这些场景中,通常需要等待系统完成更改或返回数据。
另一个关键组件是 PowerShell DSC(期望状态配置),它允许您定义基础架构(角色、功能、服务、文件、安全设置等)的期望配置,并重复应用这些状态。结合通过 WMI/CIM 获取的信息,您可以检测偏差、主动纠正偏差,并以更少的人工干预维护一致的环境。
使用 PowerShell 进行本地、远程和云管理
在本地层面,PowerShell 提供了用于管理 Active Directory 域服务、配置网络和管理服务器的 cmdlet。在 Windows 10 及更高版本中,这种集成更加深入,使您能够自动执行从创建网站到管理 Active Directory 对象和配置网络适配器的所有操作。
PSProviders 和 PSDrives是两个鲜为人知但却非常有用的组件,它们允许您将不同的存储位置(文件系统、注册表、Active Directory 等)视为可导航的驱动器。因此,您可以使用与浏览硬盘相同的语法,在远程计算机上创建 Active Directory 组、注册表项或文件夹结构。
在远程管理方面,PowerShell 集成了一套强大的功能,可以连接到一台或多台计算机并代表您执行命令。您可以使用持久的 PSSession 会话、高级远程处理技术、一对多场景(同时管理多台服务器)或一对一场景(用于调试特定案例)。当然,所有这些都必须遵循远程访问的架构和安全模型。
如今,云计算也扮演着至关重要的角色。借助Azure PowerShell 和 Azure Cloud Shell,您可以直接从命令行管理虚拟机、存储和订阅。如果您管理混合环境或完全托管在 Azure 上的环境,那么安装 Azure PowerShell 模块并熟悉它们几乎是必不可少的。
另一方面,PowerShell 也已成为管理 Microsoft 365(包括 Exchange Online、SharePoint Online、Teams、用户和许可证)的首选工具。从创建和管理帐户到管理 Exchange Online 资源(包括组、SharePoint 网站和 Microsoft Teams),所有操作都可以通过脚本进行协调,从而大幅减少 Web 门户上的手动工作。
脚本编写、流程和最佳实践
要充分利用 WMI 和 CIM 的高级自动化功能,掌握PowerShell 的管道模型至关重要。与其他 shell 不同,PowerShell 传递的不是纯文本,而是完整的对象,这使您可以非常精确地选择、排序、测量、筛选、枚举和转换信息。
学习使用管道包括正确使用选择和筛选 cmdlet,理解如何枚举复杂对象,以及如何在命令和脚本之间传递数据而不丢失信息。有条不紊地使用变量、数组和哈希表可以强化这些技能,它们充当临时数据结构,用于构建更高级的逻辑。
下一步是编写脚本:将命令打包成可重用的脚本,并添加流程控制(if、for、foreach)、从 CSV 文件或其他格式导入数据、处理用户输入、错误处理和事件日志记录等功能。所有这些都使您能够从孤立的命令过渡到更强大、更内置的工具。
在采用 WMI/CIM 的大规模自动化环境中,故障排除和错误处理尤为重要,因为网络中断、权限配置错误或类缺失等问题都可能导致流程中断,除非进行妥善管理。借助 try/catch 块、可配置的错误操作和详细的日志记录,您可以更有效地预测和应对这些情况。
最后,所有与函数和模块相关的工作都构成了一个完整的闭环:您对脚本进行签名以确保其完整性,将函数打包成模块,将这些模块分发到内部或公共存储库中,并在组织内部创建一个共享工具生态系统。这样,任何关于 WMI、CIM 或远程处理的新开发都能集成到一个连贯且易于维护的套件中。
将上述所有技术——WMI/CIM、远程会话、脚本、异步作业、DSC、Azure 和 Microsoft 365——结合起来,便可构建一个以 PowerShell 高级自动化为核心的管理环境。凭借扎实的最佳实践基础、对 CimSessions(包括 WSMan 和 DCOM)的巧妙运用以及模块化的脚本设计,您可以比仅仅依赖图形向导或独立工具更高效、更安全地管理异构基础架构。

