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 技能连载 - 系统信息采集

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

系统信息采集是运维工作的基础——新服务器上架时的资产登记、故障排查时的环境确认、容量规划时的硬件盘点、合规审计时的配置核查。PowerShell 通过 CIM/WMI、.NET 类和注册表,可以获取几乎所有的系统信息:硬件配置、操作系统详情、网络设置、已安装软件、驱动版本等。

本文将讲解如何高效采集系统信息,并生成可用的资产报告。

硬件信息采集

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
# 计算机基本信息
$os = Get-CimInstance Win32_OperatingSystem
$cs = Get-CimInstance Win32_ComputerSystem
$bios = Get-CimInstance Win32_BIOS

Write-Host "=== 系统概览 ===" -ForegroundColor Cyan
Write-Host "计算机名:$($cs.Name)"
Write-Host "制造商:$($cs.Manufacturer)"
Write-Host "型号:$($cs.Model)"
Write-Host "序列号:$($bios.SerialNumber)"
Write-Host "操作系统:$($os.Caption)"
Write-Host "版本:$($os.Version)"
Write-Host "架构:$($os.OSArchitecture)"
Write-Host "安装日期:$($os.InstallDate.ToString('yyyy-MM-dd'))"
Write-Host "最后启动:$($os.LastBootUpTime.ToString('yyyy-MM-dd HH:mm:ss'))"
Write-Host "运行时间:$([math]::Round(((Get-Date) - $os.LastBootUpTime).TotalDays, 1)) 天"

# CPU 信息
Write-Host "`n=== CPU 信息 ===" -ForegroundColor Cyan
$cpus = Get-CimInstance Win32_Processor
foreach ($cpu in $cpus) {
Write-Host "处理器:$($cpu.Name)"
Write-Host " 核心数:$($cpu.NumberOfCores),线程数:$($cpu.NumberOfLogicalProcessors)"
Write-Host " 频率:$($cpu.MaxClockSpeed) MHz"
Write-Host " 使用率:$($cpu.LoadPercentage)%"
}

# 内存信息
Write-Host "`n=== 内存信息 ===" -ForegroundColor Cyan
$totalGB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
$freeGB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
$usedGB = [math]::Round($totalGB - $freeGB, 2)
$usedPct = [math]::Round($usedGB / $totalGB * 100, 1)

Write-Host "总内存:$totalGB GB"
Write-Host "已使用:$usedGB GB ($usedPct%)"
Write-Host "可用:$freeGB GB"

# 物理内存条详情
$dimms = Get-CimInstance Win32_PhysicalMemory
foreach ($dimm in $dimms) {
$sizeGB = [math]::Round($dimm.Capacity / 1GB)
Write-Host " 槽位 $($dimm.DeviceLocator):$sizeGB GB $($dimm.Speed) MHz $($dimm.Manufacturer)"
}

执行结果示例:

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
=== 系统概览 ===
计算机名:SRV-PROD-01
制造商:Dell Inc.
型号:PowerEdge R750
序列号:ABC123DEF456
操作系统:Microsoft Windows Server 2022 Standard
版本:10.0.20348
架构:64 位
安装日期:2024-03-15
最后启动:2025-06-28 02:00:00
运行时间:16.2 天

=== CPU 信息 ===
处理器:Intel(R) Xeon(R) Gold 6348 CPU @ 2.60GHz
核心数:28,线程数:56
频率:2600 MHz
使用率:35%

=== 内存信息 ===
总内存:256 GB
已使用:185.4 GB (72.4%)
可用:70.6 GB
槽位 DIMM_A1:32 GB 3200 MHz Samsung
槽位 DIMM_A2:32 GB 3200 MHz Samsung
槽位 DIMM_B1:32 GB 3200 MHz Samsung
槽位 DIMM_B2:32 GB 3200 MHz Samsung

磁盘与网络信息

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
# 磁盘信息
Write-Host "=== 磁盘信息 ===" -ForegroundColor Cyan
$disks = Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3"
foreach ($disk in $disks) {
$totalGB = [math]::Round($disk.Size / 1GB, 2)
$freeGB = [math]::Round($disk.FreeSpace / 1GB, 2)
$usedPct = [math]::Round(($disk.Size - $disk.FreeSpace) / $disk.Size * 100, 1)
$bar = "|" + ("█" * [math]::Floor($usedPct / 5)) + ("░" * (20 - [math]::Floor($usedPct / 5))) + "|"

Write-Host "$($disk.DeviceID) $bar $usedPct% ($freeGB GB 可用 / $totalGB GB)"
}

# 网络适配器
Write-Host "`n=== 网络适配器 ===" -ForegroundColor Cyan
$adapters = Get-CimInstance Win32_NetworkAdapter | Where-Object { $_.PhysicalAdapter -and $_.NetEnabled }
foreach ($adapter in $adapters) {
Write-Host "适配器:$($adapter.Name)"
Write-Host " MAC:$($adapter.MACAddress)"
Write-Host " 速度:$([math]::Round($adapter.Speed / 1GBps, 2)) Gbps"

$config = Get-CimInstance Win32_NetworkAdapterConfiguration |
Where-Object { $_.Index -eq $adapter.Index }
if ($config.IPAddress) {
Write-Host " IP:$($config.IPAddress -join ', ')"
Write-Host " 网关:$($config.DefaultIPGateway -join ', ')"
Write-Host " DNS:$($config.DNSServerSearchOrder -join ', ')"
}
}

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
=== 磁盘信息 ===
C: |████████████████░░░░| 78.5% (43.2 GB 可用 / 200.0 GB)
D: |█████████░░░░░░░░░░░| 47.3% (263.5 GB 可用 / 500.0 GB)
E: |████████████░░░░░░░░| 62.1% (379.0 GB 可用 / 1000.0 GB)

=== 网络适配器 ===
适配器:Intel(R) Ethernet Connection X722
MAC:AA:BB:CC:DD:EE:01
速度:10 Gbps
IP:10.0.1.10
网关:10.0.1.1
DNS:10.0.1.100, 10.0.1.101

已安装软件清单

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
# 获取已安装软件列表
function Get-InstalledSoftware {
param(
[string]$SearchName,
[switch]$WithUpdates
)

$software = @()

# 从注册表读取(64位和32位)
$regPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)

foreach ($path in $regPaths) {
$items = Get-ItemProperty $path -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName }
foreach ($item in $items) {
$software += [PSCustomObject]@{
Name = $item.DisplayName
Version = $item.DisplayVersion
Publisher = $item.Publisher
InstallDate = if ($item.InstallDate) {
try { [datetime]::ParseExact($item.InstallDate, "yyyyMMdd", $null) } catch { $null }
} else { $null }
Size = if ($item.EstimatedSize) {
[math]::Round($item.EstimatedSize / 1024, 1)
} else { $null }
}
}
}

# 去重并排序
$software = $software | Sort-Object Name -Unique | Sort-Object Name

if ($SearchName) {
$software = $software | Where-Object { $_.Name -match [regex]::Escape($SearchName) }
}

return $software
}

# 列出所有软件
$all = Get-InstalledSoftware
Write-Host "已安装软件:$($all.Count) 个" -ForegroundColor Cyan
$all | Select-Object Name, Version, Publisher |
Format-Table -AutoSize | Out-String -Width 120 | Write-Host

# 搜索特定软件
$java = Get-InstalledSoftware -SearchName "Java"
Write-Host "`nJava 相关软件:" -ForegroundColor Yellow
$java | Format-Table Name, Version -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
已安装软件:127
Name Version Publisher
---- ------- ----------
7-Zip 23.01 (x64) 23.01 Igor Pavlov
Git for Windows 2.45.0 The Git Development Community
Microsoft Visual Studio Code 1.90.1 Microsoft Corporation
Node.js 20.14.0 OpenJS Foundation
PowerShell 7-x64 7.4.2 Microsoft Corporation

Java 相关软件:
Name Version
---- -------
Java 8 Update 411 (64-bit) 8.0.4110.9
Java SE Development Kit 17 17.0.11

系统信息报告函数

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
function Get-SystemReport {
<#
.SYNOPSIS
生成完整的系统信息报告
#>
param([string]$OutputPath = "C:\Reports\system-info.json")

$os = Get-CimInstance Win32_OperatingSystem
$cs = Get-CimInstance Win32_ComputerSystem
$bios = Get-CimInstance Win32_BIOS
$cpu = Get-CimInstance Win32_Processor | Select-Object -First 1

$report = [PSCustomObject]@{
CollectedAt = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Computer = @{
Name = $cs.Name
Manufacturer = $cs.Manufacturer
Model = $cs.Model
Serial = $bios.SerialNumber
Domain = $cs.Domain
}
OS = @{
Name = $os.Caption
Version = $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 = @{
Name = $cpu.Name
Cores = $cpu.NumberOfCores
Threads = $cpu.NumberOfLogicalProcessors
UsagePct = $cpu.LoadPercentage
}
Memory = @{
TotalGB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
FreeGB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
UsagePct = [math]::Round(($cs.TotalPhysicalMemory - $os.FreePhysicalMemory * 1MB) / $cs.TotalPhysicalMemory * 100, 1)
}
Disks = @(foreach ($disk in (Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3")) {
@{
Drive = $disk.DeviceID
TotalGB = [math]::Round($disk.Size / 1GB, 2)
FreeGB = [math]::Round($disk.FreeSpace / 1GB, 2)
UsagePct = [math]::Round(($disk.Size - $disk.FreeSpace) / $disk.Size * 100, 1)
}
})
}

$report | ConvertTo-Json -Depth 5 | Set-Content $OutputPath -Encoding UTF8
Write-Host "系统报告已保存:$OutputPath" -ForegroundColor Green

return $report
}

Get-SystemReport | Select-Object -Property CollectedAt |
Format-List

执行结果示例:

1
2
3
系统报告已保存:C:\Reports\system-info.json

CollectedAt : 2025-07-14 08:00:00

注意事项

  1. 权限要求:部分信息(如序列号)需要管理员权限才能读取
  2. 远程采集:使用 -ComputerName 参数可以远程采集其他机器的信息(需要 WinRM)
  3. WMI vs CIM:优先使用 Get-CimInstance(标准 WS-Man 协议),避免使用已过时的 Get-WmiObject
  4. 性能考虑:某些查询(如软件清单)需要遍历注册表,在大量机器上并行执行时注意时间
  5. 输出格式:JSON 适合程序处理,HTML 适合人类阅读,CSV 适合导入 Excel
  6. 敏感信息:序列号、IP 地址等信息属于敏感数据,报告存储和传输时注意保护