How to use WMI with Windows PowerShell scripts

Windows Management Instrumentation (WMI) is one of those tools that can change your proverbial life. But while it’s been around since the early 90s, the adoption of WMI has been slowed due to its complicated nature. Windows PowerShell has torn down this wall by making WMI much easier to use in a way that’s changing the face of IT.

Before we dive into exactly how PowerShell simplifies WMI, let’s take a look at what exactly WMI is. In the simplest terms, you can think of WMI as a library filled with resources that provide all sorts of data in a consistent and reliable format.

Wikipedia explains the purpose of WMI as a way to “define a non-proprietary set of environment-independent specifications [that] allow management information to be shared between management applications.” That’s a pretty abstract explanation, and while WMI may have started as an attempt for “environment-independence”, things have now changed, starting with what’s

considered these days to be WMI. When you hear about WMI today, it’s generally used in the context of Microsoft’s implementation of WMI via build-in providers. That’s what we’ll focus on here.

WMI can be broke down into three basic components:

Provider — grants access to managed objects and provides availability to the WMI APIClasses — a WMI representation of objects with properties and methodsNamespace — a logical grouping of classes

So how can PowerShell help make WMI easier to access?

First, let’s look at the tools PowerShell offers for WMI. There are basically five PowerShell cmdlets that make working with WMI a breeze. I will list all of them here, but I’m really only going to focus on one of them (Get-WMIObject):

Get-WmiObject – returns object(s) based on the namespace and class provided

Invoke-WmiMethod – calls WMI methods (commonly used to execute static methods)

Register-WmiEvent – used to subscribe to WMI events

Remove-WmiObject – deletes an instance of an existing WMI class (to be clear, it doesn’t delete the actual class itself, but the instance of the class you have in memory)

Set-WmiInstance – creates or updates an instance of an existing WMI class (use this one with caution as it actually writes to the WMI repository)

Now let’s tackle the biggest problem with WMI, which is figuring out exactly what’s there and what data it provides. There are several ways to get this information, but let’s start with the built-in option.

You can list providers by doing the following:

$Root = “\.ROOT:__namespace”
$WMIProv = New-Object System.Management.ManagementClass
($Root)
$WMIProv.GetInstances() | Select Name

(Granted, this is a little more complicated than the rest of the tasks. Fortunately, you shouldn’t have to do this often.)

Here is how you list the classes provided by a specific namespace (default is RootCIM2, which has all the Microsoft Win32 classes):

# On local machine
Get-WmiObject –Namespace RootSecurityCenter –List
# On Remote machine
Get-WmiObject –Namespace RootSecurityCenter –List
–Computer core
# To filter you can use wildcards
Get-WmiObject
–Namespace RootSecurityCenter –List
*firewall*
# To list the classes for HyperV on remote server
Get-WmiObject
–Namespace RootVirtualization –List
–Computer core

(This is the hard way, but you can cheat by using free tools like WMI Explorer or Microsoft’s PowerShell Scriptomatic.)

Now it’s time to get down and dirty with Get-WMIObject, which is by far the most useful of the five cmdlets. With this in your toolbox you are only one line away from almost any piece of data (Microsoft OS-related) you can think of. There are over 600 Win32 classes that expose things like CPU, memory, disk, processes, network, BIOS, USB and more. Excited? Just wait until you see how simple it is.

To get operating system info:
Get-WmiObject–class win32_OperatingSystem

To get computer system info:
Get-WmiObject–class win32_ComputerSystem

To get disk info:
Get-WmiObject–class Win32_LogicalDisk

To get network info:
Get-WmiObject –class Win32_NetworkAdapterConfiguration

Just give it a try – it really is that easy.

Let’s finish up by looking at an example script using WMI to get IP information. The useful script below replaces ipconfig and its usually awful output.

function Get-IP
{
[Cmdletbinding()]
Param(
[alias('dnsHostName')]

[Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=
$true) [string]$ComputerName = $Env:COMPUTERNAME
)
process
{
$NICs = Get-WmiObject
Win32_NetworkAdapterConfiguration -Filter
“IPEnabled=’$True’” -ComputerName $ComputerName
foreach ($Nic in $NICs)
{
$myobj = @{
Name             = $Nic.Description
MacAddress       = $Nic.MACAddress
IP4              = $Nic.IPAddress | where{$_
-match
“d+.d+.d+.d+”}
IP6              = $Nic.IPAddress | where{$_
-match “::”}
IP4Subnet        = $Nic.IPSubnet | where{$_
-match
“d+.d+.d+.d+”}
DefaultGWY       = $Nic.DefaultIPGateway |
Select -First 1
DNSServer        = $Nic.DNSServerSearchOrder
WINSPrimary      = $Nic.WINSPrimaryServer
WINSSecondary    = $Nic.WINSSecondaryServer
}
$obj = New-Object PSObject -Property $myobj
$obj.PSTypeNames.Clear()
$obj.PSTypeNames.Add(‘BSonPosh.IPInfo’)
$obj
}

}
}

You can find more general information about WMI at the Microsoft website, along with a WMI glossary of terms and Win32 class list.

Leave a Comment