PowerShell WMI vs CIM: Which to Use and Why

PowerShell WMI vs CIM: Which to Use and Why

PowerShell Tips Editor 3 min read
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 Dcom for 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-WmiObject will fail in PowerShell 7 with “cmdlet not recognized.” The fix is a global search-and-replace: Get-WmiObject -ClassGet-CimInstance -ClassName, Get-WmiObject -ComputerNameGet-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 -ComputerName fails. 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.

Send-Item -To