How to Use WMI on Windows Server 2012 R2
Windows Management Instrumentation (WMI) is Microsoft’s implementation of the Web-Based Enterprise Management (WBEM) standard and the central repository of management information on Windows systems. WMI exposes virtually every aspect of a Windows Server 2012 R2 system — hardware inventory, operating system properties, installed software, running processes, services, network configuration, disk information, and much more — through a structured, queryable interface accessible via PowerShell, VBScript, and remote management tools.
In Windows Server 2012 R2, WMI runs alongside its successor CIM (Common Information Model), and PowerShell 4.0 provides both the legacy Get-WmiObject cmdlet and the newer, preferred Get-CimInstance cmdlet. Both access WMI data, but CIM cmdlets use the WS-Management protocol and are more efficient for remote queries. This guide covers the most practical WMI use cases for server administration, including hardware inventory, service management, process monitoring, and remote WMI queries.
Prerequisites
– Windows Server 2012 R2 with PowerShell 4.0
– Administrative credentials on the local or remote server
– WMI service (winmgmt) running on target systems
– For remote WMI: Windows Firewall exceptions for WMI (TCP port 135 plus dynamic RPC ports) or WinRM configured
– Basic understanding of WMI namespaces and classes
Step 1: Verify WMI Service Status
The WMI service (Windows Management Instrumentation) must be running. Check its status:
Get-Service winmgmt | Select-Object Name, DisplayName, Status, StartType
If it is stopped, start it:
Start-Service winmgmt
Set-Service winmgmt -StartupType Automatic
Run a quick test query to confirm WMI is responding:
Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object Name, Manufacturer, Model
Step 2: Explore WMI Namespaces and Classes
WMI is organized into namespaces. The most commonly used is rootCIMV2, which contains classes for OS, hardware, and software management. Explore available namespaces:
# List root namespaces
Get-CimInstance -Namespace root -ClassName __Namespace | Select-Object Name | Sort-Object Name
List all classes in the CIMV2 namespace:
Get-CimClass -Namespace rootCIMV2 | Select-Object CimClassName | Sort-Object CimClassName | Where-Object { $_.CimClassName -like "Win32_*" }
Inspect the properties of a specific class before querying it:
Get-CimClass -ClassName Win32_LogicalDisk | Select-Object -ExpandProperty CimClassProperties | Select-Object Name, CimType
Step 3: Hardware and System Inventory with WMI
WMI is the most comprehensive source of hardware information on Windows. Gather a complete system inventory:
# Computer system information
Get-CimInstance Win32_ComputerSystem | Select-Object Name, Manufacturer, Model, SystemType, TotalPhysicalMemory
# BIOS information
Get-CimInstance Win32_BIOS | Select-Object Manufacturer, Name, Version, SerialNumber, ReleaseDate
# Processor information
Get-CimInstance Win32_Processor | Select-Object Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed, LoadPercentage
# Physical memory modules
Get-CimInstance Win32_PhysicalMemory | Select-Object BankLabel, Capacity, Speed, Manufacturer, PartNumber
# Total installed RAM in GB
$totalRAM = (Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property Capacity -Sum).Sum / 1GB
Write-Host "Total RAM: $([math]::Round($totalRAM, 2)) GB"
Step 4: Disk and Storage Information
WMI provides rich disk and partition information through multiple classes:
# Logical disk (drive letters) with free space
Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | Select-Object DeviceID, VolumeName,
@{N="SizeGB"; E={[math]::Round($_.Size/1GB,2)}},
@{N="FreeGB"; E={[math]::Round($_.FreeSpace/1GB,2)}},
@{N="UsedPct"; E={[math]::Round((($_.Size-$_.FreeSpace)/$_.Size)*100,1)}}
# Physical disk drives
Get-CimInstance Win32_DiskDrive | Select-Object Model, Size, InterfaceType, MediaType, Status
# Disk partitions
Get-CimInstance Win32_DiskPartition | Select-Object DiskIndex, Name, Size, Type, BootPartition
# Volume information
Get-CimInstance Win32_Volume -Filter "DriveType=3" | Select-Object DriveLetter, Label, FileSystem,
@{N="CapacityGB"; E={[math]::Round($_.Capacity/1GB,2)}},
@{N="FreeGB"; E={[math]::Round($_.FreeSpace/1GB,2)}}
Step 5: Network Configuration Information
Retrieve detailed network adapter configuration from WMI:
# Network adapters with IP configuration
Get-CimInstance Win32_NetworkAdapterConfiguration -Filter "IPEnabled=True" | ForEach-Object {
[PSCustomObject]@{
Description = $_.Description
MACAddress = $_.MACAddress
IPAddress = $_.IPAddress -join ", "
SubnetMask = $_.IPSubnet -join ", "
DefaultGW = $_.DefaultIPGateway -join ", "
DNS = $_.DNSServerSearchOrder -join ", "
DHCP = $_.DHCPEnabled
}
}
# All network adapters (including disabled)
Get-CimInstance Win32_NetworkAdapter | Select-Object Name, MACAddress, AdapterType, Speed, NetEnabled
Step 6: Operating System and Uptime Information
Query OS properties and calculate system uptime:
$os = Get-CimInstance Win32_OperatingSystem
$uptime = (Get-Date) - $os.LastBootUpTime
[PSCustomObject]@{
ComputerName = $os.CSName
OSName = $os.Caption
ServicePack = $os.CSDVersion
Architecture = $os.OSArchitecture
BuildNumber = $os.BuildNumber
InstallDate = $os.InstallDate
LastBoot = $os.LastBootUpTime
UptimeDays = [math]::Round($uptime.TotalDays, 1)
TotalMemoryGB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2)
FreeMemoryGB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
TotalVirtualGB = [math]::Round($os.TotalVirtualMemorySize / 1MB, 2)
FreeVirtualGB = [math]::Round($os.FreeVirtualMemory / 1MB, 2)
}
Step 7: Process and Service Management with WMI
WMI provides process and service information with additional detail not available from Get-Process:
# List top 10 processes by working set memory
Get-CimInstance Win32_Process | Sort-Object WorkingSetSize -Descending | Select-Object -First 10 `
Name, ProcessId,
@{N="MemoryMB"; E={[math]::Round($_.WorkingSetSize/1MB,1)}},
@{N="CpuSecs"; E={[math]::Round($_.KernelModeTime/10000000,2)}},
CommandLine
# Get the owner of a process (who launched it)
Get-CimInstance Win32_Process -Filter "Name='notepad.exe'" | ForEach-Object {
$owner = Invoke-CimMethod -InputObject $_ -MethodName GetOwner
"$($_.Name) ($($_.ProcessId)) — Owner: $($owner.Domain)$($owner.User)"
}
# List services with their executable paths
Get-CimInstance Win32_Service | Select-Object Name, DisplayName, State, StartMode, PathName | Sort-Object Name
Step 8: Installed Software Inventory
WMI can enumerate installed software via Win32_Product, though this class triggers Windows Installer repair checks and is slow. For fast read-only inventory, query the registry instead via WMI:
# Using Win32_Product (slow but comprehensive)
Get-CimInstance Win32_Product | Select-Object Name, Version, Vendor, InstallDate | Sort-Object Name
# Alternative: query registry for installed programs (faster)
$regPath = "HKLM:SoftwareMicrosoftWindowsCurrentVersionUninstall*"
Get-ItemProperty $regPath | Where-Object { $_.DisplayName } |
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |
Sort-Object DisplayName
Step 9: Remote WMI Queries
Query WMI on remote servers using CIM sessions, which use WS-Management (WinRM) and are more firewall-friendly than DCOM-based WMI:
# Create a CIM session to a remote server
$session = New-CimSession -ComputerName "Server01"
# Query the remote server
Get-CimInstance -CimSession $session -ClassName Win32_OperatingSystem | Select-Object CSName, Caption, LastBootUpTime
# Query multiple servers simultaneously
$servers = @("Server01","Server02","Server03")
$sessions = New-CimSession -ComputerName $servers
$diskInfo = Get-CimInstance -CimSession $sessions -ClassName Win32_LogicalDisk -Filter "DriveType=3"
$diskInfo | Select-Object PSComputerName, DeviceID,
@{N="FreeGB"; E={[math]::Round($_.FreeSpace/1GB,2)}},
@{N="SizeGB"; E={[math]::Round($_.Size/1GB,2)}} | Sort-Object PSComputerName
# Clean up sessions
Remove-CimSession $sessions
Step 10: WMI Event Subscriptions
WMI supports permanent event subscriptions that execute actions when system events occur — a powerful automation tool:
# Create a WMI event query that watches for a specific process to start
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'suspicious.exe'"
# Register a temporary event subscription (valid for current PowerShell session)
Register-CimIndicationEvent -Query $query -Action {
$process = $EventArgs.NewEvent.TargetInstance
Write-EventLog -LogName Application -Source "WMI Monitor" -EventId 9001 -EntryType Warning -Message "Suspicious process started: PID $($process.ProcessId)"
} -SourceIdentifier "ProcessWatch"
# List registered event subscriptions
Get-EventSubscriber | Select-Object SubscriptionId, SourceIdentifier, EventName
# Remove when no longer needed
Unregister-Event -SourceIdentifier "ProcessWatch"
Troubleshooting WMI Issues
If WMI queries fail or return incomplete data, the WMI repository may be corrupt. Verify its integrity:
winmgmt /verifyrepository
If verification fails, rebuild the repository (this requires a service restart and may take several minutes):
winmgmt /resetrepository
For remote WMI connectivity issues, verify firewall exceptions are in place:
netsh advfirewall firewall set rule group="Windows Management Instrumentation (WMI)" new enable=yes
Summary
WMI on Windows Server 2012 R2 is an indispensable tool for server administration, providing programmatic access to virtually every aspect of system state and configuration. Through PowerShell’s Get-CimInstance cmdlet and CIM sessions, administrators can build comprehensive inventory scripts, automate routine checks, monitor for security events using WMI event subscriptions, and gather remote server data efficiently. Understanding the key WMI classes — Win32_ComputerSystem, Win32_LogicalDisk, Win32_Process, Win32_Service, Win32_OperatingSystem — and how to filter and format their output enables sophisticated automation that would otherwise require expensive third-party monitoring tools.