PowerShell 技能连载 - CIM/WMI 高级查询

适用于 PowerShell 5.1 及以上版本

在 Windows 系统管理中,CIM(Common Information Model)和 WMI(Windows Management Instrumentation)是获取系统底层信息的核心接口。日常运维中我们经常使用 Get-CimInstance 来查询服务状态、磁盘信息等,但这仅仅是冰山一角。CIM 提供的高级查询能力——WQL 查询语言、关联遍历、事件订阅、远程会话管理——可以让你对整个 Windows 基础设施进行深度洞察。

对于管理数十台甚至上百台服务器的运维团队来说,掌握 CIM 高级查询技术意味着可以用更少的代码获取更精确的系统信息。通过 WQL 的 WHERE 子句在服务端完成数据过滤,比在客户端用 Where-Object 筛选效率高出数倍;通过 CIM 事件订阅可以实现文件变更监控、进程启停追踪等实时告警;通过 CIM 会话(CimSession)可以高效地批量管理远程主机。

本文将从 WQL 查询优化、硬件资产清单采集、CIM 事件订阅与远程管理三个维度,带你深入挖掘 CIM/WMI 的高级用法。

WQL 查询与性能优化

WQL(WMI Query Language)是专用于 WMI/CIM 的查询语言,语法类似 SQL,支持 SELECT、FROM、WHERE 等子句。很多用户习惯先获取全部实例再用 PowerShell 过滤,这在大规模查询时会产生大量不必要的数据传输。正确的做法是把过滤条件交给 WQL,让 WMI 服务端只返回符合条件的记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# ============================================================
# WQL 查询性能优化示例
# ============================================================

# 1. 基本查询:获取所有磁盘信息(低效写法)
$allDisks = Get-CimInstance -ClassName Win32_LogicalDisk
$filtered = $allDisks | Where-Object { $_.DriveType -eq 3 -and $_.FreeSpace -lt 1GB }
$filtered | Select-Object DeviceID, `
@{N='TotalGB';E={[math]::Round($_.Size/1GB,2)}}, `
@{N='FreeGB';E={[math]::Round($_.FreeSpace/1GB,2)}}, `
@{N='UsedPct';E={[math]::Round(($_.Size - $_.FreeSpace)/$_.Size*100,1)}}

# 2. WQL 优化写法:服务端过滤,仅返回本地磁盘且空间不足的记录
$query = "SELECT DeviceID, Size, FreeSpace, VolumeName " +
"FROM Win32_LogicalDisk " +
"WHERE DriveType=3 AND FreeSpace < 1073741824"
$wqlResult = Get-CimInstance -Query $query
$wqlResult | Select-Object DeviceID, VolumeName, `
@{N='TotalGB';E={[math]::Round($_.Size/1GB,2)}}, `
@{N='FreeGB';E={[math]::Round($_.FreeSpace/1GB,2)}}

# 3. 仅选择需要的属性(减少返回数据量)
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, WorkingSetSize |
Sort-Object WorkingSetSize -Descending |
Select-Object -First 10 Name, ProcessId,
@{N='MemMB';E={[math]::Round($_.WorkingSetSize/1MB,1)}}

# 4. LIKE 模糊查询:查找所有包含 "SQL" 的服务
Get-CimInstance -Query `
"SELECT Name, State, StartMode FROM Win32_Service WHERE Name LIKE '%SQL%'" |
Select-Object Name, State, StartMode

# 5. 关联查询:获取磁盘分区与逻辑磁盘的对应关系
Get-CimInstance -Query `
"ASSOCIATORS OF {Win32_DiskDrive.DeviceID='\\\\.\\PHYSICALDRIVE0'} " +
"WHERE ResultClass=Win32_DiskPartition" |
Select-Object DeviceID, Type, Size, Bootable

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
DeviceID VolumeName TotalGB FreeGB UsedPct
-------- ---------- ------- ------ -------
C: System 256.00 0.85 99.7
E: Data 500.00 0.32 99.9

Name ProcessId MemMB
---- --------- -----
chrome 12840 812.3
devenv 9456 624.7
Code 10234 418.2

Name State StartMode
---- ----- ---------
MSSQLSERVER Running Auto
SQLSERVERAGENT Stopped Manual
SQLBrowser Running Auto
SQLTELEMETRY Running Auto

DeviceID Type Size Bootable
-------- ---- ---- --------
Disk #0, Part. 0 Installable File Sys. 524288000 True
Disk #0, Part. 1 GPT: Basic Data 274877906944 False

上面的代码展示了五种不同层次的查询优化技巧。第一种是”反面教材”——先全量拉取再客户端过滤;第二种用 WQL 的 WHERE 子句在服务端完成过滤,显著减少网络传输和内存占用;第三种通过 -Property 参数限定返回字段;第四种演示 WQL 的 LIKE 模糊匹配;第五种用 ASSOCIATORS OF 语句实现跨类关联查询,可以沿着 CIM 模型的关系树遍历关联对象。

硬件资产清单采集

硬件资产清点是 IT 运维中的高频需求。通过 CIM 可以采集 CPU、内存、磁盘、网络适配器、BIOS、操作系统等完整的硬件和软件信息。下面的脚本将多种 CIM 查询组合在一起,生成一份结构化的资产报告。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# ============================================================
# 完整硬件资产清单采集脚本
# ============================================================

function Get-SystemInventory {
[CmdletBinding()]
param(
[string]$ComputerName = $env:COMPUTERNAME
)

$report = [ordered]@{}
$report['ComputerName'] = $ComputerName
$report['ScanTime'] = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'

# 1. 操作系统信息
$os = Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $ComputerName
$report['OSName'] = $os.Caption
$report['OSVersion'] = $os.Version
$report['OSArch'] = $os.OSArchitecture
$report['InstallDate']= $os.InstallDate.ToString('yyyy-MM-dd')
$report['LastBoot'] = $os.LastBootUpTime.ToString('yyyy-MM-dd HH:mm:ss')
$report['UptimeDays'] = [math]::Round(((Get-Date) - $os.LastBootUpTime).TotalDays, 1)
$report['TotalMemGB'] = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2)
$report['FreeMemGB'] = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
$report['MemUsagePct']= [math]::Round(
($os.TotalVisibleMemorySize - $os.FreePhysicalMemory) /
$os.TotalVisibleMemorySize * 100, 1)

# 2. CPU 信息
$cpus = Get-CimInstance -ClassName Win32_Processor -ComputerName $ComputerName
$report['CPUCount'] = $cpus.Count
$report['CPUDetails'] = $cpus | ForEach-Object {
[PSCustomObject]@{
Name = $_.Name
Cores = "$($_.NumberOfCores)C/$($_.NumberOfLogicalProcessors)T"
MaxClock = "$([math]::Round($_.MaxClockSpeed/1000,1)) GHz"
L2Cache = "$($_.L2CacheSize) KB"
L3Cache = "$($_.L3CacheSize) KB"
}
}

# 3. 磁盘信息
$disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" `
-ComputerName $ComputerName
$report['Disks'] = $disks | ForEach-Object {
[PSCustomObject]@{
Drive = $_.DeviceID
Label = $_.VolumeName
TotalGB = [math]::Round($_.Size/1GB, 2)
FreeGB = [math]::Round($_.FreeSpace/1GB, 2)
UsedPct = [math]::Round(($_.Size - $_.FreeSpace)/$_.Size*100, 1)
FileSystem= $_.FileSystem
}
}

# 4. 网络适配器(仅物理适配器)
$query = "SELECT Name, MACAddress, NetConnectionID, Speed, NetEnabled " +
"FROM Win32_NetworkAdapter WHERE PhysicalAdapter=True AND NetEnabled=True"
$nics = Get-CimInstance -Query $query -ComputerName $ComputerName
$report['NetworkAdapters'] = $nics | ForEach-Object {
[PSCustomObject]@{
Interface = $_.NetConnectionID
MAC = $_.MACAddress
SpeedMbps = [math]::Round($_.Speed / 1000000, 0)
}
}

# 5. 已安装软件(含版本和安装日期)
$software = Get-CimInstance -ClassName Win32_Product -ComputerName $ComputerName |
Sort-Object Name |
Select-Object -First 30 Name, Version, @{N='InstallDate';E={
if ($_.InstallDate) { $_.InstallDate.ToString('yyyy-MM-dd') } else { 'N/A' }
}}
$report['InstalledSoftware'] = $software

# 6. BIOS 和序列号(用于资产登记)
$bios = Get-CimInstance -ClassName Win32_BIOS -ComputerName $ComputerName
$cs = Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $ComputerName
$report['BIOSVersion'] = $bios.SMBIOSBIOSVersion
$report['SerialNumber'] = $bios.SerialNumber
$report['Manufacturer'] = $cs.Manufacturer
$report['Model'] = $cs.Model

return [PSCustomObject]$report
}

# 执行采集
$inventory = Get-SystemInventory

# 输出摘要
$inventory | Select-Object ComputerName, OSName, OSVersion, OSArch, `
SerialNumber, Manufacturer, Model, TotalMemGB, MemUsagePct, UptimeDays

# 输出磁盘详情
$inventory.Disks | Format-Table -AutoSize

# 输出网络适配器
$inventory.NetworkAdapters | Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ComputerName : DESKTOP-PROD01
OSName : Microsoft Windows 11 Enterprise
OSVersion : 10.0.26100
OSArch : 64-bit
SerialNumber : PF4K7X2R
Manufacturer : Dell Inc.
Model : Precision 5680
TotalMemGB : 32.00
MemUsagePct : 67.3
UptimeDays : 12.5

Drive Label TotalGB FreeGB UsedPct FileSystem
----- ----- ------- ------ ------- ----------
C: System 256.00 98.45 61.5 NTFS
D: Data 512.00 187.32 63.4 NTFS
E: Backup 1024.00 891.50 13.0 ReFS

Interface MAC SpeedMbps
--------- --- ---------
Ethernet 4C:7A:DB:12:34:56 1000
Wi-Fi 4C:7A:DB:12:34:57 867

这个 Get-SystemInventory 函数封装了六大类信息的采集逻辑:操作系统概览(含运行时间和内存使用率)、CPU 详细参数(核心数、频率、缓存)、磁盘分区与使用率、活跃的网络适配器及带宽、已安装软件清单、BIOS 序列号和硬件型号。在实际运维中,你可以将此函数配合远程 CIM 会话批量采集多台主机的资产数据,汇总到 CSV 或数据库中。

注意 Win32_Product 类的查询会比较慢(它会触发 MSI 重新配置检查),在生产环境中如果只需要软件清单,建议改用注册表路径 HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\ 来读取,效率会高很多。

CIM 事件订阅与远程管理

CIM 事件订阅是 WMI 的一项强大功能,可以监控系统中特定事件的发生,例如进程创建、文件变更、服务状态变化等。配合 CimSession,我们可以实现对远程主机的高效批量管理。下面的代码演示了三种典型的 CIM 高级应用场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# ============================================================
# CIM 事件订阅与远程管理
# ============================================================

# ---- 场景 1:进程创建事件监控 ----

# 注册 WMI 事件查询,每秒轮询一次,监控 notepad.exe 启动
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 1 " +
"WHERE TargetInstance ISA 'Win32_Process' " +
"AND TargetInstance.Name = 'notepad.exe'"

$job = Register-CimIndicationEvent -Query $query -SourceIdentifier 'MonitorNotepad'

Write-Host "已注册 notepad.exe 进程监控事件..." -ForegroundColor Green
Write-Host "请打开记事本触发事件,等待 60 秒..." -ForegroundColor Yellow

# 等待事件(60 秒超时)
$event = Wait-Event -SourceIdentifier 'MonitorNotepad' -Timeout 60

if ($event) {
$proc = $event.SourceEventArgs.NewEvent.TargetInstance
Write-Host "`n[检测到新进程]" -ForegroundColor Cyan
Write-Host " 进程名: $($proc.Name)"
Write-Host " PID: $($proc.ProcessId)"
Write-Host " 命令行: $($proc.CommandLine)"
Write-Host " 创建时间: $(Get-Date -Format 'HH:mm:ss')"
$event | Remove-Event
} else {
Write-Host "`n60 秒内未检测到 notepad.exe 启动" -ForegroundColor DarkGray
}

# 清理事件订阅
Get-EventSubscriber -SourceIdentifier 'MonitorNotepad' -ErrorAction SilentlyContinue |
Unregister-Event
Remove-Job -Name 'MonitorNotepad' -Force -ErrorAction SilentlyContinue

# ---- 场景 2:远程 CIM 会话管理 ----

# 创建到多台主机的 CIM 会话(使用当前凭据)
$computers = @('SRV-DB01', 'SRV-WEB01', 'SRV-FILE01')

$sessions = $computers | ForEach-Object {
$session = $null
try {
$session = New-CimSession -ComputerName $_ -ErrorAction Stop
Write-Host "[OK] 已连接: $_" -ForegroundColor Green
} catch {
Write-Host "[FAIL] 连接失败: $_ - $($_.Exception.Message)" -ForegroundColor Red
}
$session
} | Where-Object { $_ -ne $null }

# 批量查询磁盘空间
$sessions | ForEach-Object {
$computer = $_.ComputerName
Get-CimInstance -CimSession $_ -Query `
"SELECT DeviceID, Size, FreeSpace FROM Win32_LogicalDisk WHERE DriveType=3" |
ForEach-Object {
[PSCustomObject]@{
Server = $computer
Drive = $_.DeviceID
TotalGB = [math]::Round($_.Size/1GB, 2)
FreeGB = [math]::Round($_.FreeSpace/1GB, 2)
UsedPct = [math]::Round(($_.Size - $_.FreeSpace)/$_.Size*100, 1)
}
}
} | Format-Table -AutoSize

# 批量查询服务状态
$serviceName = 'WinRM'
$sessions | ForEach-Object {
Get-CimInstance -CimSession $_ -Query `
"SELECT State, StartMode FROM Win32_Service WHERE Name='$serviceName'" |
ForEach-Object {
[PSCustomObject]@{
Server = $_PSItem.PSComputerName
Service = $serviceName
State = $_.State
Start = $_.StartMode
}
}
} | Format-Table -AutoSize

# 清理会话
$sessions | Remove-CimSession
Write-Host "`n已清理所有 CIM 会话" -ForegroundColor Green

# ---- 场景 3:文件变更实时监控 ----

# 监控指定目录下的文件创建事件(利用 CIM 的 __InstanceCreationEvent)
$watchPath = 'C:\Temp\Watch'
if (-not (Test-Path $watchPath)) { New-Item -Path $watchPath -ItemType Directory | Out-Null }

# 使用 .NET FileSystemWatcher 作为轻量替代(CIM 事件开销较大)
$watcher = [System.IO.FileSystemWatcher]::new($watchPath)
$watcher.Filter = '*.*'
$watcher.EnableRaisingEvents = $true

# 注册文件创建事件
$action = {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$time = $Event.TimeGenerated.ToString('HH:mm:ss.fff')
Write-Host "[$time] $changeType : $name" -ForegroundColor Yellow
}

Register-ObjectEvent -InputObject $watcher -EventName Created -Action $action |
Out-Null

Write-Host "正在监控目录: $watchPath" -ForegroundColor Green
Write-Host "创建文件触发事件,30 秒后自动停止..." -ForegroundColor Yellow

Start-Sleep -Seconds 30

# 清理
$watcher.EnableRaisingEvents = $false
Get-EventSubscriber | Unregister-Event
Get-Job | Remove-Job -Force

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
已注册 notepad.exe 进程监控事件...
请打开记事本触发事件,等待 60 秒...

[检测到新进程]
进程名: notepad.exe
PID: 28456
命令行: "C:\Windows\System32\notepad.exe" C:\Temp\test.txt
创建时间: 14:23:17

[OK] 已连接: SRV-DB01
[OK] 已连接: SRV-WEB01
[FAIL] 连接失败: SRV-FILE01 - The RPC server is unavailable.

Server Drive TotalGB FreeGB UsedPct
------ ----- ------- ------ -------
SRV-DB01 C: 256.00 45.30 82.3
SRV-DB01 D: 1024.00 312.50 69.5
SRV-WEB01 C: 128.00 89.20 30.3

Server Service State Start
------ ------- ----- -----
SRV-DB01 WinRM Running Auto
SRV-WEB01 WinRM Running Auto

已清理所有 CIM 会话

正在监控目录: C:\Temp\Watch
创建文件触发事件,30 秒后自动停止...
[14:25:03.127] Created : report.csv
[14:25:08.342] Created : config.json
[14:25:15.891] Created : backup.zip

第一个场景展示了 CIM 事件订阅的核心模式:通过 Register-CimIndicationEvent 注册一个后台事件查询任务,WMI 服务每秒(WITHIN 1)检查一次是否有新的 notepad.exe 进程出现,事件触发后通过 Wait-Event 接收详细信息。这种模式可以扩展到监控服务停止、磁盘空间低于阈值等运维告警场景。

第二个场景演示了 CimSession 的批量远程管理能力。与每次调用 Get-CimInstance -ComputerName 不同,CimSession 会建立持久的连接通道,后续的多个查询复用同一会话,避免了反复认证和连接建立的开销。在管理大量服务器时,这种方式的效率提升非常明显。

第三个场景中,鉴于 CIM 文件监控事件在系统开销上较重,代码也演示了使用 .NET 的 FileSystemWatcher 作为轻量级替代方案,这在实际生产中更为实用。

注意事项

  1. 优先使用 Get-CimInstance 而非 Get-WmiObjectGet-WmiObject 在 PowerShell 3.0 后已被标记为过时,Get-CimInstance 使用标准 WS-Man 协议,跨平台兼容性更好,且返回的对象更符合 PowerShell 管道规范。

  2. WQL 过滤优于 Where-Object 过滤:通过 WQL 的 WHERE 子句或 -Filter 参数在服务端完成数据筛选,避免将全量数据传输到客户端再过滤,在查询远程主机时性能差距尤为明显。

  3. Win32_Product 类的查询陷阱Win32_Product 在枚举时会触发每个 MSI 包的完整性检查,非常耗时且可能引发 Windows Installer 重新配置。生产环境中采集软件清单应改用注册表路径读取。

  4. CIM 事件订阅的资源开销WITHIN 子句指定的轮询间隔不宜过短,频繁轮询会增加 CPU 和 WMI 服务的负担。一般建议设置为 5 秒以上。对于高频事件监控,优先考虑 .NET 的 FileSystemWatcherSystem.Diagnostics.TraceEvent 等原生 API。

  5. 远程 CIM 连接的防火墙配置:CIM 远程管理依赖 WinRM 服务(端口 5985/5986)。目标主机必须启用 WinRM(Enable-PSRemoting -Force),防火墙放行对应端口,且两端的信任主机配置需匹配(Set-Item WSMan:\localhost\Client\TrustedHosts)。

  6. CIM 类名在不同系统上的差异:部分 CIM 类(如 Win32_PhysicalMemory)在不同 Windows 版本上返回的属性可能不同。建议在正式脚本中先用 Get-CimClass 检查目标类是否存在及其属性列表,避免因属性缺失导致脚本异常退出。

PowerShell 技能连载 - WMI 与 CIM 查询

适用于 PowerShell 5.1 及以上版本(Windows)

Windows 管理规范(WMI)是 Windows 平台上用于管理和查询系统信息的核心基础设施。从硬盘序列号到操作系统版本,从网络适配器状态到 BIOS 信息,WMI 几乎能访问系统的每一个角落。长期以来,PowerShell 通过 Get-WmiObject cmdlet 为管理员提供了便捷的 WMI 查询能力。

然而,Get-WmiObject 基于 DCOM/RPC 协议进行远程通信,存在防火墙配置复杂、性能开销大等问题。从 PowerShell 3.0 开始,微软引入了基于 CIM(Common Information Model)标准的新一代 cmdlet——Get-CimInstance。CIM cmdlet 默认使用 WS-Man(WinRM)协议,不仅更安全、更高效,而且与跨平台标准 DMTF 对齐,代表了 Windows 系统管理的未来方向。

本文将对比 WMI 和 CIM 两套 cmdlet 的使用方式,并通过实际场景演示如何用 CIM 查询硬件信息、远程管理服务器,以及构建高效的系统清单脚本。

WMI 与 CIM 的基本对比

我们先来看两套 cmdlet 在查询本地系统信息时的差异。以下代码分别使用 Get-WmiObjectGet-CimInstance 获取操作系统基本信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 传统 WMI 方式(PowerShell 2.0 引入,已标记为弃用)
$os = Get-WmiObject -Class Win32_OperatingSystem
Write-Host "操作系统: $($os.Caption)"
Write-Host "版本: $($os.Version)"
Write-Host "安装日期: $($os.InstallDate)"
Write-Host "上次启动: $($os.LastBootUpTime)"

# 现代 CIM 方式(PowerShell 3.0 引入,推荐使用)
$osCim = Get-CimInstance -ClassName Win32_OperatingSystem
Write-Host "操作系统: $($osCim.Caption)"
Write-Host "版本: $($osCim.Version)"
Write-Host "安装日期: $($osCim.InstallDate)"
Write-Host "上次启动: $($osCim.LastBootUpTime)"

注意输出中日期格式的差异:Get-WmiObject 返回原始的 WMI 时间字符串(如 20250101120000.000000+480),而 Get-CimInstance 自动将其转换为可读的 DateTime 对象,这一点在日常使用中非常方便。

1
2
3
4
操作系统: Microsoft Windows 11 Pro
版本: 10.0.26100
安装日期: 2025-01-15 10:30:00
上次启动: 2025-10-05 22:14:33

查询硬件信息

CIM 在硬件清单收集方面非常强大。下面的脚本演示了如何一次性收集 CPU、内存、磁盘和网络适配器的关键信息,并格式化输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 查询 CPU 信息
$cpu = Get-CimInstance -ClassName Win32_Processor
foreach ($proc in $cpu) {
Write-Host "=== CPU 信息 ==="
Write-Host "名称: $($proc.Name)"
Write-Host "核心数: $($proc.NumberOfCores)"
Write-Host "逻辑处理器: $($proc.NumberOfLogicalProcessors)"
Write-Host "最大频率: $($proc.MaxClockSpeed) MHz"
Write-Host ""
}

# 查询物理内存
$mem = Get-CimInstance -ClassName Win32_PhysicalMemory
$totalMemGB = [math]::Round(($mem | Measure-Object -Property Capacity -Sum).Sum / 1GB, 2)
Write-Host "=== 内存信息 ==="
Write-Host "总内存: ${totalMemGB} GB"
foreach ($slot in $mem) {
$sizeGB = [math]::Round($slot.Capacity / 1GB, 2)
Write-Host " 插槽 $($slot.DeviceLocator): ${sizeGB} GB - $($slot.Speed) MHz"
}
Write-Host ""

# 查询磁盘信息
$disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
Write-Host "=== 磁盘信息 ==="
foreach ($disk in $disks) {
$freeGB = [math]::Round($disk.FreeSpace / 1GB, 2)
$totalGB = [math]::Round($disk.Size / 1GB, 2)
$percent = [math]::Round(($disk.FreeSpace / $disk.Size) * 100, 1)
Write-Host " 盘符: $($disk.DeviceID)"
Write-Host " 总空间: ${totalGB} GB | 剩余: ${freeGB} GB | 可用率: ${percent}%"
Write-Host ""
}

这段脚本展示了 CIM 查询的典型模式:用 -ClassName 指定 WMI 类名,用 -Filter 进行服务端筛选(比客户端 Where-Object 更高效),然后用 foreach 遍历结果进行格式化输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
=== CPU 信息 ===
名称: Intel(R) Core(TM) i7-14700K
核心数: 20
逻辑处理器: 28
最大频率: 5600 MHz

=== 内存信息 ===
总内存: 32 GB
插槽 DIMM_A0: 16 GB - 5600 MHz
插槽 DIMM_B0: 16 GB - 5600 MHz

=== 磁盘信息 ===
盘符: C:
总空间: 512 GB | 剩余: 234.56 GB | 可用率: 45.8%

盘符: D:
总空间: 2048 GB | 剩余: 1567.89 GB | 可用率: 76.6%

使用 CIM 会话进行远程查询

CIM 相比 WMI 的一大优势是远程管理的简便性。通过 CimSession,你可以同时管理多台服务器,并且可以选择 DCOM 或 WinRM 协议。这在管理老旧系统(不支持 WinRM)时特别有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 定义目标服务器列表
$servers = @("SRV-DC01", "SRV-WEB01", "SRV-DB01")

# 创建 CIM 会话(默认使用 WinRM)
$sessions = New-CimSession -ComputerName $servers -ErrorAction SilentlyContinue

# 批量查询所有服务器的操作系统和内存使用情况
$results = foreach ($session in $sessions) {
$os = Get-CimInstance -CimSession $session -ClassName Win32_OperatingSystem
foreach ($item in $os) {
$totalMemGB = [math]::Round($item.TotalVisibleMemorySize / 1MB, 2)
$freeMemGB = [math]::Round($item.FreePhysicalMemory / 1MB, 2)
$memUsage = [math]::Round(($item.TotalVisibleMemorySize - $item.FreePhysicalMemory) / $item.TotalVisibleMemorySize * 100, 1)

[PSCustomObject]@{
Server = $session.ComputerName
OS = $item.Caption
TotalMemGB = $totalMemGB
FreeMemGB = $freeMemGB
MemUsage = "$memUsage%"
Uptime = (Get-Date) - $item.LastBootUpTime
}
}
}

# 输出结果表格
$results | Format-Table -AutoSize

# 使用完毕后关闭会话
Remove-CimSession -CimSession $sessions

上面的脚本展示了 CIM 会话的完整生命周期:创建会话、执行查询、格式化输出、最后清理会话。注意 New-CimSession 一次性建立了到所有服务器的连接,后续查询复用这些连接,避免了重复认证的开销。

1
2
3
4
5
Server   OS                                    TotalMemGB FreeMemGB MemUsage Uptime
------ -- ---------- --------- -------- ------
SRV-DC01 Microsoft Windows Server 2022 Standard 32.00 12.45 61.1% 45.12:34:56
SRV-WEB01 Microsoft Windows Server 2022 Datacenter 64.00 28.90 54.8% 12.08:15:30
SRV-DB01 Microsoft Windows Server 2025 Standard 128.00 45.67 64.3% 02.16:42:18

使用 WQL 筛选与高级查询

WQL(WMI Query Language)是一种类似 SQL 的查询语言,可以在服务端完成数据过滤,减少网络传输量。Get-CimInstance-Filter 参数接受简化的 WQL 条件,而 -Query 参数则支持完整的 WQL 语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 使用 -Filter 参数进行简单筛选(推荐方式)
# 查找所有已启用但未连接的网络适配器
$disconnectedAdapters = Get-CimInstance -ClassName Win32_NetworkAdapter `
-Filter "NetEnabled = true AND NetConnectionStatus != 2"

foreach ($adapter in $disconnectedAdapters) {
Write-Host "适配器: $($adapter.Name)"
Write-Host " MAC 地址: $($adapter.MACAddress)"
Write-Host " 速度: $([math]::Round($adapter.Speed / 1Mbps, 2)) Mbps"
Write-Host " 状态: 未连接"
Write-Host ""
}

# 使用 -Query 参数执行完整的 WQL 查询
# 查找启动类型为自动但当前未运行的服务
$stoppedAutoServices = Get-CimInstance -Query @"
SELECT Name, DisplayName, State, StartMode
FROM Win32_Service
WHERE StartMode = 'Auto' AND State != 'Running'
"@

Write-Host "=== 未运行的自动启动服务 ==="
foreach ($svc in $stoppedAutoServices) {
Write-Host " [$($svc.Name)] $($svc.DisplayName) - 状态: $($svc.State)"
}

# 关联查询:通过 __RELPATH 获取关联的磁盘分区
$diskDrive = Get-CimInstance -ClassName Win32_DiskDrive | Select-Object -First 1
$partitions = Get-CimAssociatedInstance -InputObject $diskDrive -ResultClassName Win32_DiskPartition

Write-Host ""
Write-Host "=== 磁盘分区关联查询 ==="
Write-Host "磁盘: $($diskDrive.Model)"
foreach ($part in $partitions) {
Write-Host " 分区 $($part.Name): $($part.Size / 1GB -as [int]) GB - 类型: $($part.Type)"
}

Get-CimAssociatedInstance 是 CIM cmdlet 的独有功能,用于遍历 WMI 对象之间的关联关系。传统 WMI cmdlet 没有直接等价的方法,需要手动构造关联查询,这也是推荐迁移到 CIM 的重要理由之一。

1
2
3
4
5
6
7
8
9
10
11
12
13
适配器: Intel(R) Ethernet Controller I225-V
MAC 地址: AA:BB:CC:DD:EE:FF
速度: 1000 Mbps
状态: 未连接

=== 未运行的自动启动服务 ===
[Spooler] Print Spooler - 状态: Stopped
[WSearch] Windows Search - 状态: Stopped

=== 磁盘分区关联查询 ===
磁盘: Samsung SSD 990 PRO 2TB
分区 磁盘 #0,分区 #0: 512 GB - 类型: GPT: System
分区 磁盘 #0,分区 #1: 1536 GB - 类型: GPT: Basic Data

构建系统清单报告

将前面的知识综合起来,我们可以构建一个实用的系统清单报告脚本。这个脚本收集关键系统信息并生成结构化的报告对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
function Get-SystemInventory {
<#
.SYNOPSIS
收集本地或远程系统的硬件和软件清单信息。
#>
param(
[string[]]$ComputerName = $env:COMPUTERNAME
)

$session = New-CimSession -ComputerName $ComputerName -ErrorAction Stop

foreach ($s in $session) {
$os = Get-CimInstance -CimSession $s -ClassName Win32_OperatingSystem
$cs = Get-CimInstance -CimSession $s -ClassName Win32_ComputerSystem
$bios = Get-CimInstance -CimSession $s -ClassName Win32_BIOS
$cpus = Get-CimInstance -CimSession $s -ClassName Win32_Processor
$disks = Get-CimInstance -CimSession $s -ClassName Win32_LogicalDisk -Filter "DriveType=3"

$cpuNames = @()
foreach ($cpu in $cpus) {
$cpuNames += "$($cpu.Name) ($($cpu.NumberOfCores)C/$($cpu.NumberOfLogicalProcessors)T)"
}

$diskInfo = @()
foreach ($disk in $disks) {
$diskInfo += [PSCustomObject]@{
Drive = $disk.DeviceID
Label = $disk.VolumeName
TotalGB = [math]::Round($disk.Size / 1GB, 1)
FreeGB = [math]::Round($disk.FreeSpace / 1GB, 1)
Percent = "$([math]::Round($disk.FreeSpace / $disk.Size * 100, 1))%"
}
}

$totalMemGB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
$uptime = (Get-Date) - $os.LastBootUpTime

[PSCustomObject]@{
ComputerName = $s.ComputerName
Manufacturer = $cs.Manufacturer
Model = $cs.Model
SerialNumber = $bios.SerialNumber
BIOSVersion = $bios.SMBIOSBIOSVersion
OS = $os.Caption
OSBuild = $os.BuildNumber
CPUs = $cpuNames -join "; "
TotalMemGB = $totalMemGB
Disks = $diskInfo
BootTime = $os.LastBootUpTime
Uptime = "{0:dd}天 {0:hh}时 {0:mm}分" -f $uptime
}
}

Remove-CimSession -CimSession $session
}

# 执行清单收集并查看结果
$inventory = Get-SystemInventory
$inventory | Format-List ComputerName, Manufacturer, Model, SerialNumber, BIOSVersion, OS, OSBuild, CPUs, TotalMemGB, BootTime, Uptime
$inventory.Disks | Format-Table -AutoSize

这个函数展示了 CIM 查询的工程化实践:参数化的计算机名、会话复用、错误处理、结构化输出对象。你可以将它放入自己的工具模块中,在日常运维中反复调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ComputerName : DESKTOP-WORKSTATION
Manufacturer : Gigabyte Technology Co., Ltd.
Model : Z790 AORUS MASTER
SerialNumber : GG2401001234
BIOSVersion : F12
OS : Microsoft Windows 11 Pro
OSBuild : 26100
CPUs : Intel(R) Core(TM) i7-14700K (20C/28T)
TotalMemGB : 32
BootTime : 2025-10-05 22:14:33
Uptime : 00天 09时 45分

Drive Label TotalGB FreeGB Percent
----- ----- ------- ------ -------
C: Windows 512.0 234.6 45.8%
D: Data 2048.0 1567.9 76.6%
E: Backup 4096.0 3890.2 95.0%

注意事项

  1. 优先使用 CIM cmdletGet-WmiObject 在 PowerShell 5.1 中已标记为弃用,在 PowerShell 7 的 Windows 版本中仍然可用但建议迁移。新项目应一律使用 Get-CimInstanceInvoke-CimMethod 等 CIM 系列 cmdlet。

  2. 服务端筛选优于客户端筛选:始终优先使用 -Filter 参数在服务端过滤数据(如 -Filter "DriveType=3"),而不是将全部结果拉回本地再用 Where-Object 过滤。前者只传输需要的数据,后者在 WMI 类数据量大时会产生明显的性能差距。

  3. CIM 会话需要清理:通过 New-CimSession 创建的会话在使用完毕后务必调用 Remove-CimSession 释放资源。未清理的会话会占用服务器端的 WinRM 连接配额,在大量并发场景下可能导致后续连接失败。

  4. 注意 DCOM 回退场景:如果目标机器不支持 WinRM(如老旧的 Windows Server 2003),可以在 New-CimSession 时通过 -SessionOption 指定 DCOM 协议:New-CimSessionOption -Protocol Dcom。但 DCOM 的端口配置更复杂,防火墙规则更多,建议统一部署 WinRM。

  5. WMI 类名大小写不敏感但保持一致:PowerShell 中 Win32_OperatingSystemwin32_operatingsystem 效果相同,但在脚本中应统一使用 PascalCase 命名(如 Win32_OperatingSystem),以提高代码可读性和团队协作一致性。

  6. 远程查询需要管理员权限:无论是 WMI 还是 CIM,远程查询都需要目标机器的本地管理员权限,并且 WinRM 服务必须处于运行状态。可以使用 Test-WSMan 命令快速验证远程机器的 WinRM 连通性。

PowerShell 技能连载 - WMI 与 CIM 查询

适用于 PowerShell 5.1 及以上版本(Windows)

Windows Management Instrumentation(WMI)是 Windows 操作系统内置的管理信息基础设施,它以统一的接口暴露了硬件、操作系统、应用程序的海量信息——从 CPU 温度到磁盘健康状态,从进程列表到安装的补丁,几乎所有系统信息都可以通过 WMI 获取。PowerShell 通过 CIM(Common Information Model)cmdlet 提供了对 WMI 的现代化访问方式。

本文将系统讲解 WMI/CIM 的核心概念、查询语法、常用场景,以及如何构建高效的信息采集脚本。

WMI 与 CIM 的关系

WMI 是微软对 WBEM(Web-Based Enterprise Management)标准的实现,而 CIM 是 WMI 底层的数据模型。PowerShell 提供了两套 cmdlet 来访问 WMI 数据:

  • 旧版 WMI cmdletGet-WmiObjectInvoke-WmiMethod 等(已弃用)
  • 新版 CIM cmdletGet-CimInstanceInvoke-CimMethod 等(推荐)

CIM cmdlet 的优势在于:支持 WinRM 远程连接(而非 DCOM)、更好的序列化、与 WS-Man 协议兼容。所有新脚本都应使用 CIM cmdlet。

1
2
3
4
5
6
7
# 查看可用的 CIM 类数量
$cimClasses = Get-CimClass | Select-Object -ExpandProperty CimClassName
Write-Host "系统中共有 $($cimClasses.Count) 个 CIM 类"

# 搜索与磁盘相关的 CIM 类
Get-CimClass -ClassName *Disk* | Select-Object CimClassName |
Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
系统中共有 1287 个 CIM 类

CimClassName
------------
Win32_DiskDrive
Win32_LogicalDisk
Win32_DiskPartition
Win32_MappedLogicalDisk
CIM_DiskDrive
CIM_LogicalDisk

基础信息查询

最常用的场景是查询系统硬件和操作系统信息。以下示例展示了如何获取关键的系统信息:

1
2
3
4
5
6
7
8
9
10
11
12
# 操作系统信息
$os = Get-CimInstance -ClassName Win32_OperatingSystem
[PSCustomObject]@{
系统 = $os.Caption
版本 = $os.Version
架构 = $os.OSArchitecture
计算机名 = $os.CSName
安装日期 = $os.InstallDate.ToString('yyyy-MM-dd')
最后启动 = $os.LastBootUpTime.ToString('yyyy-MM-dd HH:mm:ss')
可用内存GB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
总内存GB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2)
}

执行结果示例:

1
2
3
4
5
6
7
8
系统       : Microsoft Windows 11 Pro
版本 : 10.0.22631
架构 : 64-bit
计算机名 : DESKTOP-WORK01
安装日期 : 2024-03-15
最后启动 : 2025-05-04 08:30:00
可用内存GB : 8.45
总内存GB : 31.89
1
2
3
4
5
6
7
8
9
10
11
12
13
# CPU 信息
Get-CimInstance -ClassName Win32_Processor |
Select-Object Name, NumberOfCores, NumberOfLogicalProcessors,
MaxClockSpeed, L2CacheSize, L3CacheSize |
Format-List

# BIOS 信息(含序列号,适合资产盘点)
Get-CimInstance -ClassName Win32_BIOS |
Select-Object SerialNumber, Manufacturer, SMBIOSBIOSVersion, ReleaseDate

# 主板信息
Get-CimInstance -ClassName Win32_BaseBoard |
Select-Object Manufacturer, Product, SerialNumber, Version

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Name                    : Intel(R) Core(TM) i7-13700K
NumberOfCores : 16
NumberOfLogicalProcessors: 24
MaxClockSpeed : 3400
L2CacheSize : 24576
L3CacheSize : 30720

SerialNumber : BTFC427001XZ
Manufacturer : American Megatrends International, LLC.
SMBIOSBIOSVersion : 1.28.0
ReleaseDate : 2025-01-15

Manufacturer : ASUSTeK COMPUTER INC.
Product : ProArt Z790-CREATOR
SerialNumber : 2308475091
Version : Rev 1.xx

使用 WQL 过滤查询

WQL(WMI Query Language)是类似 SQL 的查询语言,可以在服务端过滤数据,减少网络传输量。对于远程查询,使用 -Filter 参数比在客户端用 Where-Object 过滤高效得多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查找所有固定磁盘(非可移动、非网络驱动器)
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" |
Select-Object DeviceID,
@{N='容量GB'; E={[math]::Round($_.Size/1GB,2)}},
@{N='已用GB'; E={[math]::Round(($_.Size - $_.FreeSpace)/1GB,2)}},
@{N='可用GB'; E={[math]::Round($_.FreeSpace/1GB,2)}},
@{N='使用率%'; E={[math]::Round(($_.Size - $_.FreeSpace)/$_.Size*100,1)}},
FileSystem |
Format-Table -AutoSize

# 查找所有运行中的服务
$runningServices = Get-CimInstance -ClassName Win32_Service -Filter "State='Running'"
Write-Host "正在运行的服务数量:$($runningServices.Count)"

# 查找占用内存超过 100MB 的进程
Get-CimInstance -ClassName Win32_Process -Filter "WorkingSetSize > 104857600" |
Select-Object Name, ProcessId,
@{N='内存MB'; E={[math]::Round($_.WorkingSetSize/1MB,1)}} |
Sort-Object 内存MB -Descending |
Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
DeviceID 容量GB 已用GB 可用GB 使用率% FileSystem
-------- ------ ------ ------ -------- ----------
C: 476.92 285.34 191.58 59.8 NTFS
D: 931.51 642.18 289.33 68.9 NTFS

正在运行的服务数量:147

Name ProcessId 内存MB
---- --------- ------
chrome 8234 842.3
Code 12045 624.7
msedge 5678 312.5

磁盘健康与 SMART 信息

通过 WMI 可以获取磁盘的健康状态,特别是 SSD 的磨损程度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 获取物理磁盘信息
Get-CimInstance -ClassName Win32_DiskDrive |
Select-Object Model, SerialNumber, Size,
@{N='总容量GB'; E={[math]::Round($_.Size/1GB,2)}},
InterfaceType, MediaType, Status |
Format-Table -AutoSize

# 查询磁盘分区与挂载点映射
$partitions = Get-CimInstance -ClassName Win32_DiskPartition
$logicalDisks = Get-CimInstance -ClassName Win32_LogicalDisk

foreach ($disk in (Get-CimInstance -ClassName Win32_DiskDrive)) {
Write-Host "`n磁盘:$($disk.Model)" -ForegroundColor Cyan
Write-Host " 接口:$($disk.InterfaceType)"
Write-Host " 大小:$([math]::Round($disk.Size/1GB,2)) GB"
Write-Host " 状态:$($disk.Status)"
}

执行结果示例:

1
2
3
4
5
6
7
8
9
Model           SerialNumber      总容量GB InterfaceType MediaType  Status
----- ------------ -------- ------------- --------- ------
Samsung SSD 870 S4TPNF0X123456 476.92 IDE Fixed hard OK
WDC WD10EZEX WD-WMC4E0K12345 931.51 IDE Fixed hard OK

磁盘:Samsung SSD 870 EVO 500GB
接口:SCSI
大小:476.92 GB
状态:OK

网络配置查询

WMI 存储了完整的网络适配器信息,包括 IP 地址、MAC 地址、DHCP 状态等:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 获取活跃的网络适配器信息
Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled=True" |
Select-Object Description,
@{N='IPAddress'; E={$_.IPAddress -join ', '}},
@{N='SubnetMask'; E={$_.IPSubnet -join ', '}},
DefaultIPGateway,
@{N='DNSServers'; E={$_.DNSServerSearchOrder -join ', '}},
DHCPEnabled,
MACAddress |
Format-List

# 查询网络适配器物理信息
Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "NetConnectionStatus=2" |
Select-Object Name, AdapterType, Speed,
@{N='速度Mbps'; E={[math]::Round($_.Speed/1MB,0)}} |
Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
Description     : Intel(R) Ethernet Controller I225-V
IPAddress : 192.168.1.100
SubnetMask : 255.255.255.0
DefaultIPGateway: 192.168.1.1
DNSServers : 8.8.8.8, 8.8.4.4
DHCPEnabled : True
MACAddress : A0:B1:C2:D3:E4:F5

Name AdapterType 速度Mbps
---- ------------ --------
Intel(R) Ethernet Controller Ethernet 802.3 1000

软件与补丁查询

WMI 是获取已安装软件和系统补丁信息的重要来源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查询已安装的软件
Get-CimInstance -ClassName Win32_Product |
Select-Object Name, Version, Vendor, InstallDate |
Sort-Object Name |
Format-Table -AutoSize

# 查询最近的系统更新
Get-CimInstance -ClassName Win32_QuickFixEngineering |
Sort-Object InstalledOn -Descending |
Select-Object -First 10 HotFixID, Description, InstalledOn |
Format-Table -AutoSize

# 检查特定 KB 是否已安装
$kb = 'KB5034441'
$installed = Get-CimInstance -ClassName Win32_QuickFixEngineering -Filter "HotFixID='$kb'"
if ($installed) {
Write-Host "$kb 已安装于 $($installed.InstalledOn.ToString('yyyy-MM-dd'))" -ForegroundColor Green
} else {
Write-Host "$kb 未安装" -ForegroundColor Red
}

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
Name                    Version    Vendor          InstallDate
---- ------- ------ -----------
Microsoft Visual C++... 14.40.33... Microsoft Co... 2025-01-10
7-Zip 24.08 (x64) 24.08 Igor Pavlov 2025-02-15
Mozilla Firefox 125.0.1 Mozilla 2025-04-20

HotFixID Description InstalledOn
-------- ----------- -----------
KB5036908 Security Update 2025-04-25
KB5036892 Update 2025-04-22
KB5034441 Security Update 2025-04-10

KB5034441 已安装于 2025-04-10

注意Win32_Product 查询会触发 Windows Installer 重新配置检查,速度很慢且可能影响系统稳定性。对于软件清单,建议改用注册表查询 HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*

构建系统信息采集函数

将常用的 WMI 查询封装为可复用函数,方便在运维脚本中调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function Get-SystemInventory {
<#
.SYNOPSIS
采集系统完整信息用于资产盘点
#>
[CmdletBinding()]
param(
[string]$ComputerName = $env:COMPUTERNAME
)

$session = New-CimSession -ComputerName $ComputerName

$os = Get-CimInstance -CimSession $session -ClassName Win32_OperatingSystem
$cs = Get-CimInstance -CimSession $session -ClassName Win32_ComputerSystem
$cpu = Get-CimInstance -CimSession $session -ClassName Win32_Processor
$disk = Get-CimInstance -CimSession $session -ClassName Win32_LogicalDisk -Filter "DriveType=3"
$bios = Get-CimInstance -CimSession $session -ClassName Win32_BIOS

$result = [PSCustomObject]@{
ComputerName = $cs.Name
Manufacturer = $cs.Manufacturer
Model = $cs.Model
SerialNumber = $bios.SerialNumber
OS = $os.Caption
OSVersion = $os.Version
Architecture = $os.OSArchitecture
InstallDate = $os.InstallDate.ToString('yyyy-MM-dd')
LastBoot = $os.LastBootUpTime.ToString('yyyy-MM-dd HH:mm:ss')
UptimeDays = [math]::Round((Get-Date) - $os.LastBootUpTime).TotalDays, 1)
CPU = $cpu.Name
CPUCores = $cpu.NumberOfCores
CPULogical = $cpu.NumberOfLogicalProcessors
TotalRAM_GB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
FreeRAM_GB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
Disks = $disk | ForEach-Object {
[PSCustomObject]@{
Drive = $_.DeviceID
SizeGB = [math]::Round($_.Size/1GB, 2)
FreeGB = [math]::Round($_.FreeSpace/1GB, 2)
UsedPct = [math]::Round(($_.Size - $_.FreeSpace) / $_.Size * 100, 1)
}
}
}

Remove-CimSession -CimSession $session
$result
}

# 采集本机信息
Get-SystemInventory | Format-List

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ComputerName : DESKTOP-WORK01
Manufacturer : ASUSTeK COMPUTER INC.
Model : ProArt Z790-CREATOR
SerialNumber : 2308475091
OS : Microsoft Windows 11 Pro
OSVersion : 10.0.22631
Architecture : 64-bit
InstallDate : 2024-03-15
LastBoot : 2025-05-04 08:30:00
UptimeDays : 1.1
CPU : Intel(R) Core(TM) i7-13700K
CPUCores : 16
CPULogical : 24
TotalRAM_GB : 31.89
FreeRAM_GB : 8.45
Disks : {@{Drive=C:; SizeGB=476.92; FreeGB=191.58; UsedPct=59.8}, @{Drive=D:; SizeGB=931.51; FreeGB=289.33; UsedPct=68.9}}

注意事项

  1. 优先使用 CIM cmdletGet-CimInstance 优于 Get-WmiObject,后者在 PowerShell 7 中已被弃用
  2. 远程连接方式:CIM cmdlet 默认使用 WS-Man(WinRM)协议,兼容性优于旧版 DCOM;可用 New-CimSession 建立持久会话
  3. WQL 过滤:使用 -Filter 参数在服务端过滤数据,比管道 Where-Object 更高效,尤其对远程查询
  4. 避免频繁查询 Win32_Product:该类会触发 Windows Installer 重新配置,可能导致短暂的系统卡顿
  5. 权限要求:部分 WMI 类(如安全相关)需要管理员权限才能查询
  6. CIM 会话管理:批量查询时使用 New-CimSession 建立持久会话,避免每次查询都建立新连接