PowerShell WMI vs CIM: Which to Use and Why

Your existing scripts use Get-WmiObject everywhere, and they work fine — until someone runs them on PowerShell 7 and every WMI call fails with “the term ‘Get-WmiObject’ is not recognized.” That is because Get-WmiObject was removed from PowerShell 7. The modern replacement is Get-CimInstance, which uses a cleaner protocol, better error handling, and full cross-platform support. Understanding PowerShell WMI vs CIM makes the migration straightforward and the new queries more reliable. This post covers the differences, migration patterns, and CIM sessions.
Why WMI Was Replaced by CIM
WMI (Windows Management Instrumentation) has existed since Windows 2000. The Get-WmiObject cmdlet used DCOM (Distributed COM) for remote queries — a protocol that requires a wide range of firewall ports to be open and has known security concerns. CIM (Common Information Model) cmdlets use WS-Man (WinRM), the same protocol used by PowerShell Remoting, which is firewall-friendly (single port 5985/5986) and standards-based. PowerShell Core (v6+) dropped the Windows-specific DCOM stack entirely, removing Get-WmiObject with it.
Protocol Difference: DCOM vs WinRM
Understanding the protocol difference explains why existing scripts may need updates for remote queries:
- Get-WmiObject remote: uses DCOM over RPC, requires ports 135, 445, and a dynamic range (49152-65535). Firewall-unfriendly.
- Get-CimInstance remote: uses WS-Man (WinRM) over port 5985 (HTTP) or 5986 (HTTPS) by default. Firewall-friendly.
- Get-CimInstance with DCOM fallback: possible via
New-CimSessionOption -Protocol Dcomfor legacy machines without WinRM.
# Verify WinRM is available on a target before using CIM
Test-WSMan -ComputerName "Server01" -ErrorAction SilentlyContinue
Syntax Comparison
The migration from Get-WmiObject to Get-CimInstance is mostly straightforward — the class names are identical and the filtering syntax is similar:
# WMI (Windows PowerShell 5.1 only — removed in PS7)
Get-WmiObject -Class Win32_OperatingSystem
Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'"
Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name='svchost.exe'"
# CIM (Windows PowerShell 5.1 AND PowerShell 7 — preferred)
Get-CimInstance -ClassName Win32_OperatingSystem
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceID='C:'"
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name='svchost.exe'"
SystemDirectory : C:\Windows\system32
BuildNumber : 22621
Caption : Microsoft Windows 11 Enterprise
CimSession for Persistent Connections
A CimSession holds an open connection to a remote computer, avoiding reconnection overhead on every query. This is the CIM equivalent of a PSSession for remoting:
$cs = New-CimSession -ComputerName "Server01"
# Run multiple queries over the same session
$os = Get-CimInstance -CimSession $cs -ClassName Win32_OperatingSystem
$disk = Get-CimInstance -CimSession $cs -ClassName Win32_LogicalDisk -Filter "DeviceID='C:'"
$cpu = Get-CimInstance -CimSession $cs -ClassName Win32_Processor
Write-Host "OS: $($os.Caption)"
Write-Host "Disk Free: $([Math]::Round($disk.FreeSpace/1GB, 1)) GB"
Write-Host "CPU: $($cpu.Name)"
Remove-CimSession $cs
Migrate Common WMI Queries to CIM
Most common WMI class names map directly to CIM. Here are the most frequent patterns:
# System info
# WMI: Get-WmiObject Win32_ComputerSystem
Get-CimInstance Win32_ComputerSystem | Select-Object Name, TotalPhysicalMemory, NumberOfLogicalProcessors
# Disk space
# WMI: Get-WmiObject Win32_LogicalDisk -Filter "DriveType=3"
Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" |
Select-Object DeviceID,
@{N='FreeGB'; E={[Math]::Round($_.FreeSpace/1GB,1)}},
@{N='TotalGB';E={[Math]::Round($_.Size/1GB,1)}}
# Services
# WMI: Get-WmiObject Win32_Service -Filter "State='Stopped' AND StartMode='Auto'"
Get-CimInstance Win32_Service -Filter "State='Stopped' AND StartMode='Auto'" |
Select-Object Name, DisplayName, State
# Network adapters
# WMI: Get-WmiObject Win32_NetworkAdapterConfiguration -Filter "IPEnabled=True"
Get-CimInstance Win32_NetworkAdapterConfiguration -Filter "IPEnabled=True" |
Select-Object Description, IPAddress, DefaultIPGateway
CIM on PowerShell 7 Linux
On Linux and macOS, PowerShell 7 supports a subset of CIM classes via OMI (Open Management Infrastructure). The Win32 namespace is not available, but MI/OMI classes work for querying Linux system information when the OMI server is installed:
# On Linux with OMI installed, query basic system info
# Most Win32 classes are Windows-only
# Cross-platform alternative: use /proc, /sys, or platform cmdlets
$isWindows = $PSVersionTable.Platform -eq 'Win32NT'
if ($isWindows) {
Get-CimInstance Win32_OperatingSystem
} else {
# Linux/macOS — use platform-appropriate commands
uname -a
}
Common Errors and Fixes
-
Get-WmiObject removed entirely in PowerShell 7. Scripts that use
Get-WmiObjectwill fail in PowerShell 7 with “cmdlet not recognized.” The fix is a global search-and-replace:Get-WmiObject -Class→Get-CimInstance -ClassName,Get-WmiObject -ComputerName→Get-CimInstance -ComputerName. Test on a staging system first. -
CIM uses WinRM by default — DCOM fallback needs CIM session option. If a remote machine does not have WinRM enabled,
Get-CimInstance -ComputerNamefails. Create a CIM session with DCOM transport for legacy machines:$opt = New-CimSessionOption -Protocol Dcom; $cs = New-CimSession -ComputerName "OldServer" -SessionOption $opt.
Related Cmdlets / See Also
Wrapping Up
Migrate from Get-WmiObject to Get-CimInstance now — the syntax change is minimal, the reliability improvement is significant, and the compatibility with PowerShell 7 is essential for cross-platform scripts. Use CimSession for persistent remote connections, and fall back to DCOM via New-CimSessionOption only for legacy machines without WinRM enabled.


