Chapter 18. WMI: Windows Management Instrumentation

by Mar 26, 2012

Windows Management Instrumentation (WMI) is a technique available on all Windows systems starting with Windows 2000. WMI can provide you with a wealth of information about the Windows configuration and setup. It works both locally and remotely, and PowerShell makes accessing WMI a snap.

WMI Quick Start

To work with WMI you need to know just a little bit of theory. Let's check out what the terms "class" and "object" stand for.

A "class" pretty much is like the "kind of an animal". There are dogs, cats, horses, and each kind is a class. So there is always only one class of a kind.

An "object" works like an "animal", so there are zillions of real dogs, cats, and horses. So, there may be one, ten, thousands, or no objects (or "instances") of a class. Let's take the class "mammoth". There are no instances of this class these days.

WMI works the same. If you'd like to know something about a computer, you ask WMI about a class, and WMI returns the objects. When you ask for the class "Win32_BIOS", you get back exactly one instance (or object) because your computer has just one BIOS. When you ask for "Win32_Share", you get back a number of instances, one for each share. And when you ask for "Win32_TapeDrive", you get back nothing because most likely, your computer has no built-in tape drive. Tape drives thus work like mammoths in the real world. While there is a class ("kind"), there is no more instance.

Retrieving Information

How do you ask WMI for objects? It's easy! Just use the cmdlet Get-WmiObject. It accepts a class name and returns objects, just like the cmdlet name and its parameter suggest:

PS> Get-WmiObject -Class Win32_BIOS

SMBIOSBIOSVersion : RKYWSF21
Manufacturer      : Phoenix Technologies LTD
Name              : Phoenix TrustedCore(tm) NB Release SP1 1.0
SerialNumber      : 701KIXB007922
Version           : PTLTD  - 6040000

Exploring WMI Classes

As you can see, working with WMI does not require much knowledge. It does require though that you know the name of a WMI class that represents what you are after. Fortunately, Get-WmiObject can also work like a dictionary and look up WMI class names for you. This will get you all WMI class names that have the keyword "print" in them:

PS> Get-WmiObject -List Win32_*Print*

   NameSpace: ROOTcimv2

Name                                Methods              Properties
----                                -------              ----------
Win32_PrinterConfiguration          {}                   {BitsPerPel, Captio...
Win32_PrinterSetting                {}                   {Element, Setting}
Win32_PrintJob                      {Pause, Resume}      {Caption, Color, Da...
Win32_Printer                       {SetPowerState, R... {Attributes, Availa...
Win32_PrinterDriver                 {StartService, St... {Caption, ConfigFil...
Win32_TCPIPPrinterPort              {}                   {ByteCount, Caption...
Win32_PrinterShare                  {}                   {Antecedent, Depend...
Win32_PrinterDriverDll              {}                   {Antecedent, Depend...
Win32_PrinterController             {}                   {AccessState, Antec...

Swallowing The Red Pill

By default, PowerShell limits the information WMI returns to you so you don't get carried away. It's pretty much like in the movie "The Matrix": you need to decide whether you want to swallow the blue pill and live in a simple world, or whether you dare to swallow the red pill and see the real world. By default, you live in the blue-pill-world with only limited information.

PS> Get-WmiObject -Class Win32_BIOS

SMBIOSBIOSVersion : 02LV.MP00.20081121.hkk
Manufacturer      : Phoenix Technologies Ltd.
Name              : Phoenix SecureCore(tm) NB Version 02LV.MP00.20081121.hkk
SerialNumber      : ZAMA93HS600210
Version           : SECCSD - 6040000

To see the red-pill-world, pipe the results to Select-Object and ask it to show all available properties:

PS> Get-WmiObject -Class Win32_BIOS | Select-Object -Property *

Status                : OK
Name                  : Phoenix SecureCore(tm) NB Version
                        02LV.MP00.20081121.hkk
Caption               : Phoenix SecureCore(tm) NB Version
                        02LV.MP00.20081121.hkk
SMBIOSPresent         : True
__GENUS               : 2
__CLASS               : Win32_BIOS
__SUPERCLASS          : CIM_BIOSElement
__DYNASTY             : CIM_ManagedSystemElement
__RELPATH             : Win32_BIOS.Name="Phoenix SecureCore(tm) NB Version
                        02LV.MP00.20081121.hkk",SoftwareElementID="Phoenix
                        SecureCore(tm) NB Version 02LV.MP00.20081121.hkk",Softw
                        areElementState=3,TargetOperatingSystem=0,Version="SECC
                        SD - 6040000"
__PROPERTY_COUNT      : 27
__DERIVATION          : {CIM_BIOSElement, CIM_SoftwareElement,
                        CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER              : DEMO5
__NAMESPACE           : rootcimv2
__PATH                : \DEMO5rootcimv2:Win32_BIOS.Name="Phoenix
                        SecureCore(tm) NB Version
                        02LV.MP00.20081121.hkk",SoftwareElementID="Phoenix
                        SecureCore(tm) NB Version 02LV.MP00.20081121.hkk",Softw
                        areElementState=3,TargetOperatingSystem=0,Version="SECC
                        SD - 6040000"
BiosCharacteristics   : {4, 7, 8, 9...}
BIOSVersion           : {SECCSD - 6040000, Phoenix SecureCore(tm) NB Version
                        02LV.MP00.20081121.hkk, Ver 1.00PARTTBL}
BuildNumber           :
CodeSet               :
CurrentLanguage       :
Description           : Phoenix SecureCore(tm) NB Version
                        02LV.MP00.20081121.hkk
IdentificationCode    :
InstallableLanguages  :
InstallDate           :
LanguageEdition       :
ListOfLanguages       :
Manufacturer          : Phoenix Technologies Ltd.
OtherTargetOS         :
PrimaryBIOS           : True
ReleaseDate           : 20081121000000.000000+000
SerialNumber          : ZAMA93HS600210
SMBIOSBIOSVersion     : 02LV.MP00.20081121.hkk
SMBIOSMajorVersion    : 2
SMBIOSMinorVersion    : 5
SoftwareElementID     : Phoenix SecureCore(tm) NB Version
                        02LV.MP00.20081121.hkk
SoftwareElementState  : 3
TargetOperatingSystem : 0
Version               : SECCSD - 6040000
Scope                 : System.Management.ManagementScope
Path                  : \DEMO5rootcimv2:Win32_BIOS.Name="Phoenix
                        SecureCore(tm) NB Version
                        02LV.MP00.20081121.hkk",SoftwareElementID="Phoenix
                        SecureCore(tm) NB Version 02LV.MP00.20081121.hkk",Softw
                        areElementState=3,TargetOperatingSystem=0,Version="SECC
                        SD - 6040000"
Options               : System.Management.ObjectGetOptions
ClassPath             : \DEMO5rootcimv2:Win32_BIOS
Properties            : {BiosCharacteristics, BIOSVersion, BuildNumber,
                        Caption...}
SystemProperties      : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}
Qualifiers            : {dynamic, Locale, provider, UUID}
Site                  :
Container             :

Once you see the real world, you can pick the properties you find interesting and then put together a custom selection. Note that PowerShell adds a couple of properties to the object which all start with "__". These properties are available on all WMI objects. __Server is especially useful because it always reports the name of the computer system the WMI object came from. Once you start retrieving WMI information remotely, you should always add __Server to the list of selected properties.

PS> Get-WmiObject Win32_BIOS | Select-Object __Server, Manufacturer, SerialNumber, Version

__SERVER            Manufacturer        SerialNumber        Version
--------            ------------        ------------        -------
DEMO5               Phoenix Technolo... ZAMA93HS600210      SECCSD - 6040000

Filtering WMI Results

Often, there are more instances of a class than you need. For example, when you query for Win32_NetworkAdapter, you get all kinds of network adapters, including virtual adapters and miniports.

PowerShell can filter WMI results client-side using Where-Object. So, to get only objects that have a MACAddress, you could use this line:

PS> Get-WmiObject Win32_NetworkAdapter | Where-Object { $_.MACAddress -ne $null } |
>>
Select-Object Name, MACAddress, AdapterType
>>
Name MACAddress AdapterType ---- ---------- ----------- Intel(R) 82567LM-Gigabi... 00:13:77:B9:F2:64 Ethernet 802.3 RAS Async Adapter 20:41:53:59:4E:FF Wide Area Network (WAN) Intel(R) WiFi Link 5100... 00:22:FA:D9:E1:50 Ethernet 802.3

Client-side filtering is easy because it really just uses Where-Object to pick out those objects that fulfill a given condition. However, it is slightly inefficient as well. All WMI objects need to travel to your computer first before PowerShell can pick out the ones you want.

If you only expect a small number of objects and/or if you are retrieving objects from a local machine, there is no need to create more efficient code. If however you are using WMI remotely via network and/or have to deal with hundreds or even thousands of objects, you should instead use server-side filters.

These filters are transmitted to WMI along with your query, and WMI only returns the wanted objects in the first place. Since these filters are managed by WMI and not PowerShell, they use WMI syntax and not PowerShell syntax. Have a look:

PS> Get-WmiObject Win32_NetworkAdapter -Filter 'MACAddress != NULL' |
>>
Select-Object Name, MACAddress, AdapterType
>>
Name MACAddress AdapterType ---- ---------- ----------- Intel(R) 82567LM-Gigabi... 00:13:77:B9:F2:64 Ethernet 802.3 RAS Async Adapter 20:41:53:59:4E:FF Wide Area Network (WAN) Intel(R) WiFi Link 5100... 00:22:FA:D9:E1:50 Ethernet 802.3

Simple filters like the one above are almost self-explanatory. WMI uses different operators ("!=" instead of "-ne" for inequality) and keywords ("NULL" instead of $null), but the general logic is the same.

Sometimes, however, WMI filters can be tricky. For example, to find all network cards that have an IP address assigned to them, in PowerShell (using client-side filtering) you would use:

PS> Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPAddress -ne $null } |
>>
Select-Object Caption, IPAddress, MACAddress
>>
Caption IPAddress MACAddress ------- --------- ---------- [00000011] Intel(R) WiF... {192.168.2.109, fe80::a... 00:22:FA:D9:E1:50

If you translated this to a server-side WMI filter, it fails:

PS> Get-WmiObject Win32_NetworkAdapterConfiguration -Filter 'IPAddress != NULL' |
>>
Select-Object Caption, IPAddress, MACAddress
>>
Get-WmiObject : Invalid query "select * from Win32_NetworkAdapterConfiguration where IPAddress != NULL"

The reason for this is the nature of the IPAddress property. When you look at the results from your client-side filtering, you'll notice that the column IPAddress has values in braces and displays more than one IP address. The property IPAddress is an array. WMI filters cannot check array contents.

So in this scenario, you would have to either stick to client-side filtering or search for another object property that is not an array and could still separate network cards with IP address from those without. There happens to be a property called IPEnabled that does just that:

PS> Get-WmiObject Win32_NetworkAdapterConfiguration -Filter 'IPEnabled = true' |
>>
Select-Object Caption, IPAddress, MACAddress
>>
Caption IPAddress MACAddress ------- --------- ---------- [00000011] Intel(R) WiF... {192.168.2.109, fe80::a... 00:22:FA:D9:E1:50

A special WMI filter operator is "LIKE". It works almost like PowerShell’s comparison operator -like. Use "%" instead of "*" for wildcards, though. So, to find all services with the keyword "net" in their name, try this:

PS> Get-WmiObject Win32_Service -Filter 'Name LIKE "%net%"' | Select-Object Name, DisplayName, State

Name                       DisplayName                State
----                       -----------                -----
aspnet_state               ASP.NET-Zustandsdienst     Stopped
Net Driver HPZ12           Net Driver HPZ12           Stopped
Netlogon                   Netlogon                   Running
Netman                     Network Connections        Running
NetMsmqActivator           Net.Msmq Listener Adapter  Stopped
NetPipeActivator           Net.Pipe Listener Adapter  Stopped
netprofm                   Network List Service       Running
NetTcpActivator            Net.Tcp Listener Adapter   Stopped
NetTcpPortSharing          Net.Tcp Port Sharing Se... Stopped
WMPNetworkSvc              Windows Media Player Ne... Running

PowerShell supports the [WmiSearcher] type accelerator, which you can use to achieve basically the same thing you just did with the –query parameter:

$searcher = [WmiSearcher]"select caption,commandline from Win32_Process where name like 'p%'"
$searcher.Get()| Format-Table [a-z]* -Wrap

Direct WMI Object Access

Every WMI instance has its own unique path. This path is important if you want to access a particular instance directly. The path of a WMI object is located in the __PATH property. First use a "traditional" query to list this property and find out what it looks like:

Get-WmiObject Win32_Service | ForEach-Object { $_.__PATH }
\JSMITH-PCrootcimv2:Win32_Service.Name="AeLookupSvc"
\JSMITH-PCrootcimv2:Win32_Service.Name="AgereModemAudio"
\JSMITH-PCrootcimv2:Win32_Service.Name="ALG"
\JSMITH-PCrootcimv2:Win32_Service.Name="Appinfo"
\JSMITH-PCrootcimv2:Win32_Service.Name="AppMgmt"
\JSMITH-PCrootcimv2:Win32_Service.Name="Ati External Event Utility"
\JSMITH-PCrootcimv2:Win32_Service.Name="AudioEndpointBuilder"
\JSMITH-PCrootcimv2:Win32_Service.Name="Audiosrv"
\JSMITH-PCrootcimv2:Win32_Service.Name="Automatic LiveUpdate - Scheduler"
\JSMITH-PCrootcimv2:Win32_Service.Name="BFE"
\JSMITH-PCrootcimv2:Win32_Service.Name="BITS"
\JSMITH-PCrootcimv2:Win32_Service.Name="Browser"
(...)

The path consists basically of the class name as well as one or more key properties. For services, the key property is Name and is the English-language name of the service. If you want to work directly with a particular service through WMI, specify its path and do a type conversion. Use either the [wmi] type accelerator or the underlying [System.Management.ManagementObject] .NET type:

[wmi]"Win32_Service.Name='Fax'"
ExitCode  : 1077
Name      : Fax
ProcessId : 0
StartMode : Manual
State     : Stopped
Status    : OK

In fact, you don’t necessarily need to specify the name of the key property as long as you at least specify its value. This way, you’ll find all the properties of a specific WMI instance right away.

$disk = [wmi]'Win32_LogicalDisk="C:"'
$disk.FreeSpace
10181373952
[int]($disk.FreeSpace / 1MB)
9710
$disk | Format-List [a-z]*
Status                       :
Availability                 :
DeviceID                     : C:
StatusInfo                   :
Access                       : 0
BlockSize                    :
Caption                      : C:
Compressed                   : False
ConfigManagerErrorCode       :
ConfigManagerUserConfig      :
CreationClassName            : Win32_LogicalDisk
Description                  : Local hard drive
DriveType                    : 3
ErrorCleared                 :
ErrorDescription             :
ErrorMethodology             :
FileSystem                   : NTFS
FreeSpace                    : 10181373952
InstallDate                  :
LastErrorCode                :
MaximumComponentLength       : 255
MediaType                    : 12
Name                         : C:
NumberOfBlocks               :
PNPDeviceID                  :
PowerManagementCapabilities  :
PowerManagementSupported     :
ProviderName                 :
Purpose                      :
QuotasDisabled               :
QuotasIncomplete             :
QuotasRebuilding             :
Size                         : 100944637952
SupportsDiskQuotas           : False
SupportsFileBasedCompression : True
SystemCreationClassName      : Win32_ComputerSystem
SystemName                   : JSMITH-PC
VolumeDirty                  :
VolumeName                   :
VolumeSerialNumber           : AC039C05

Changing System Configuration

WMIs primary purpose is to read information about the current system configuration but it can also be used to make changes to a system. Most WMI object properties are read-only, but some are writeable, too. In addition, a number of WMI objects contain methods that you can call to make changes.

Note that WMI objects returned by PowerShell Remoting always are read-only. They cannot be used to change the remote system. If you want to change a remote system using WMI objects, you must connect to the remote system using the -ComputerName parameter provided by Get-WmiObject.

Modifying Properties

Most of the properties that you find in WMI objects are read-only. There are few, though, that can be modified. For example, if you want to change the description of a drive, add new text to the VolumeName property of the drive:

$drive = [wmi]"Win32_LogicalDisk='C:'"
$drive.VolumeName = "My Harddrive"
$drive.Put()
Path          : \.rootcimv2:Win32_LogicalDisk.DeviceID="C:"
RelativePath  : Win32_LogicalDisk.DeviceID="C:"
Server        : .
NamespacePath : rootcimv2
ClassName     : Win32_LogicalDisk
IsClass       : False
IsInstance    : True
IsSingleton   : False

Three conditions must be met before you can modify a property:

  • The property must be writeable. Most properties are read-only.
  • You require the proper permissions for modifications. The drive description applies to all users of a computer so only administrators may modify them.
  • You must use Put() to save the modification. Without Put(), the modification will not be written back to the system.

Invoking WMI Methods

WMI objects derived from the Win32_Process class have a Terminate() method you can use to terminate a process. Of course it is much easier to terminate a process with Stop-Process, so why would you use WMI? Because WMI supports remote connections. Stop-Process can only stop processes on your local machine.

This line would kill all instances of the Windows Editor "notepad.exe" on your local machine:

Get-WmiObject Win32_Process -Filter "name='notepad.exe'" |
ForEach-Object { $_.Terminate().ReturnValue }

Add the parameter -ComputerName to Get-WmiObject, and you'd be able to kill notepads on one or more remote machines – provided you have Administrator privileges on the remote machine.

For every instance that Terminate() closes, it returns an object with a number of properties. Only the property ReturnValue is useful, though, because it tells you whether the call succeeded. That's why it is generally a good idea to add ".ReturnValue" to all calls of a WMI method. A return value of 0 generally indicates success, any other code failure. To find out what the error codes mean you would have to surf to an Internet search engine and enter the WMI class name (like "Win32_Process"). One of the first links will guide you to the Microsoft MSDN documentation page for that class. It lists all codes and clear text translations for all properties and method calls.

If you already know the process ID of a process, you can work on the process directly just as you did in the last section because the process ID is the key property of processes. For example, you could terminate the process with the ID 1234 like this:

 ([wmi]"Win32_Process='1234'").Terminate()

If you’d rather check your hard disk drive C: for errors, the proper invocation is:

 ([wmi]"Win32_LogicalDisk='C:'").Chkdsk(...

However, since this method requires additional arguments, the question here is what you should specify. Invoke the method without parentheses in order to get initial brief instructions:

([wmi]"Win32_LogicalDisk='C:'").Chkdsk
MemberType          : Method
OverloadDefinitions : {System.Management.ManagementBaseObject Chkdsk(System.Boolean FixErrors, System.Boolean
                       VigorousIndexCheck, System.Boolean SkipFolderCycle, System.Boolean ForceDismount, Syst
                      em.Boolean RecoverBadSectors, System.Boolean OkToRunAtBootUp)}
TypeNameOfValue     : System.Management.Automation.PSMethod
Value               : System.Management.ManagementBaseObject Chkdsk(System.Boolean FixErrors, System.Boolean
                      VigorousIndexCheck, System.Boolean SkipFolderCycle, System.Boolean ForceDismount, Syste
                      m.Boolean RecoverBadSectors, System.Boolean OkToRunAtBootUp)
Name                : Chkdsk
IsInstance          : True

Get-Member will tell you which methods a WMI object supports:

PS> Get-WmiObject Win32_Process | Get-Member -MemberType Method
   TypeName: System.Management.ManagementObject#rootcimv2Win32_Process

Name           MemberType Definition
----           ---------- ----------
AttachDebugger Method     System.Management.ManagementBaseObject AttachDebugger()
GetOwner       Method     System.Management.ManagementBaseObject GetOwner()
GetOwnerSid    Method     System.Management.ManagementBaseObject GetOwnerSid()
SetPriority    Method     System.Management.ManagementBaseObject SetPriority(System.Int32 Priority)
Terminate      Method     System.Management.ManagementBaseObject Terminate(System.UInt32 Reason)

Static Methods

There are WMI methods not just in WMI objects that you retrieved with Get-WmiObject. Some WMI classes also support methods. These methods are called "static".

If you want to renew the IP addresses of all network cards, use the Win32_NetworkAdapterConfiguration class and its static method RenewDHCPLeaseAll():

 ([wmiclass]"Win32_NetworkAdapterConfiguration").RenewDHCPLeaseAll().ReturnValue

You get the WMI class by using type conversion. You can either use the [wmiclass] type accelerator or the underlying [System.Management.ManagementClass].

The methods of a WMI class are also documented in detail inside WMI. For example, you get the description of the Win32Shutdown() method of the Win32_OperatingSystem class like this:

$class = [wmiclass]'Win32_OperatingSystem'
$class.Options.UseAmendedQualifiers = $true
(($class.methods["Win32Shutdown"]).Qualifiers["Description"]).Value
The Win32Shutdown method provides the full set of shutdown options supported by Win32
operating systems. The method returns an integer value that can be interpretted as follows: 0 Successful completion. Other for integer values other than those listed above, refer to Win32 error code documentation.

If you’d like to learn more about a WMI class or a method, navigate to an Internet search page like Google and specify as keyword the WMI class name, as well as the method. It’s best to limit your search to the Microsoft MSDN pages: Win32_NetworkAdapterConfiguration RenewDHCPLeaseAll site:msdn2.microsoft.com.

Using WMI Auto-Documentation

Nearly every WMI class has a built-in description that explains its purpose. You can view this description only if you first set a hidden option called UseAmendedQualifiers to $true. Once that’s done, the WMI class will readily supply information about its function:

$class = [wmiclass]'Win32_LogicalDisk'
$class.psbase.Options.UseAmendedQualifiers = $true
($class.psbase.qualifiers["description"]).Value
The Win32_LogicalDisk class represents a data source that resolves to an actual local storage
device on a Win32 system. The class returns both local as well as mapped logical disks.
However, the recommended approach is to use this class for obtaining information on local
disks and to use the Win32_MappedLogicalDisk for information on mapped logical disk.

In a similarly way, all the properties of the class are documented. The next example retrieves the documentation for the property VolumeDirty and explains what its purpose is:

$class = [wmiclass]'Win32_LogicalDisk'
$class.psbase.Options.UseAmendedQualifiers = $true
($class.psbase.properties["VolumeDirty"]).Type
Boolean
(($class.psbase.properties["VolumeDirty"]).Qualifiers["Description"]).Value
The VolumeDirty property indicates whether the disk requires chkdsk to be run at next boot up time. 
The property is applicable to only those instances of logical disk that represent a physical disk in
the machine. It is not applicable to mapped logical drives.

WMI Events

WMI returns not only information but can also wait for certain events. If the events occur, an action will be started. In the process, WMI can alert you when one of the following things involving a WMI instance happens:

  • __InstanceCreationEvent: A new instance was added such as a new process was started or a new file created.
  • __InstanceModificationEvent: The properties of an instance changed. For example, the FreeSpace property of a drive was modified.
  • __InstanceDeletionEvent: An instance was deleted, such as a program was shut down or a file deleted.
  • __InstanceOperationEvent: This is triggered in all three cases.

You can use these to set up an alarm signal. For example, if you want to be informed as soon as Notepad is started, type:

Select * from __InstanceCreationEvent WITHIN 1 WHERE targetinstance ISA 'Win32_Process' AND
targetinstance.name = 'notepad.exe'

WITHIN specifies the time interval of the inspection and “WITHIN 1” means that you want to be informed no later than one second after the event occurs. The shorter you set the interval, the more effort involved, which means that WMI will require commensurately more computing power to perform your task. As long as the interval is kept at not less than one second, the computation effort will be scarcely perceptible. Here is an example:

$alarm = New-Object Management.EventQuery
$alarm.QueryString = "Select * from __InstanceCreationEvent WITHIN 1 WHERE targetinstance ISA 'Win32_Process' AND `
targetinstance.name = 'notepad.exe'"
$watch = New-Object Management.ManagementEventWatcher $alarm Start Notepad after issuing a wait command:” $result = $watch.WaitForNextEvent() Get target instance of Notepad:” $result.targetinstance Access the live instance:” $path = $result.targetinstance.__path $live = [wmi]$path # Close Notepad using the live instance $live.terminate()

Using WMI Remotely

WMI comes with built-in remoting so you can retrieve WMI objects not just from your local machine but also across the network. WMI uses "traditional" remoting techniques like DCOM which are also used by the Microsoft Management Consoles.

To be able to use WMI remoting, your network must support DCOM calls (thus, the firewall needs to be set up accordingly). Also, you need to have Administrator privileges on the target machine.

Accessing WMI Objects on Another Computer

Use the -ComputerName parameter of Get-WmiObject to access another computer system using WMI. Then specify the name of the computer after it:

Get-WmiObject -ComputerName pc023 Win32_Process

You can also specify a comma-separated list of a number of computers and return information from all of them. The parameter -ComputerName accepts an array of computer names. Anything that returns an array of computer names or IP addresses can be valid input. This line, for example, would read computer names from a file:

Get-WmiObject Win32_Process -ComputerName (Get-Content c:serverlist.txt)

If you want to log on to the target system using another user account, use the –Credential parameter to specify additional log on data as in this example:

$credential = Get-Credential
Get-WmiObject -ComputerName pc023 -Credential $credential Win32_Process

In addition to the built-in remoting capabilities, you can use Get-WmiObject via PowerShell Remoting (if you have set up PowerShell Remoting correctly). Here, you send the WMI command off to the remote system:

Invoke-Command { Get-WmiObject Win32_BIOS } -ComputerName server12, server16

Note that all objects returned by PowerShell Remoting are read-only and do not contain methods anymore. If you want to change WMI properties or call WMI methods, you need to do this inside the script block you send to the remote system – so it needs to be done before PowerShell Remoting sends back objects to your own system.

WMI Background Information

WMI has a hierarchical structure much like a file system does. Up to now, all the classes that you have used have come from the WMI “directory” rootcimv2. Third-party vendors can create additional WMI directories, known as Namespaces, and put in them their own classes, which you can use to control software, like Microsoft Office or hardware like switches and other equipment.

Because the topmost directory in WMI is always named root, from its location you can inspect existing namespaces. Get a display first of the namespaces on this level:

Get-WmiObject -Namespace root __Namespace | Format-Wide Name
subscription                                           DEFAULT
MicrosoftDfs                                           CIMV2
Cli                                                    nap
SECURITY                                               RSOP
Infineon                                               WMI
directory                                              Policy
ServiceModel                                           SecurityCenter
MSAPPS12                                               Microsoft
aspnet

As you see, the cimv2 directory is only one of them. What other directories are shown here depends on the software and hardware that you use. For example, if you use Microsoft Office, you may find a directory called MSAPPS12. Take a look at the classes in it:

Get-WmiObject -Namespace rootmsapps12 -List | Where-Object { $_.Name.StartsWith("Win32_") }
Win32_PowerPoint12Tables                               Win32_Publisher12PageNumber
Win32_Publisher12Hyperlink                             Win32_PowerPointSummary
Win32_Word12Fonts                                      Win32_PowerPointActivePresentation
Win32_OutlookDefaultFileLocation                       Win32_Word12Document
Win32_ExcelAddIns                                      Win32_PowerPoint12Table
Win32_ADOCoreComponents                                Win32_Publisher12SelectedTable
Win32_Word12CharacterStyle                             Win32_Word12Styles
Win32_OutlookSummary                                   Win32_Word12DefaultFileLocation
Win32_WordComAddins                                    Win32_PowerPoint12AlternateStartupLoc
Win32_OutlookComAddins                                 Win32_ExcelCharts
Win32_Word12Settings                                   Win32_FrontPageActiveWeb
Win32_OdbcDriver                                       Win32_AccessProject
Win32_Word12StartupFileLocation                        Win32_ExcelActiveWorkbook
Win32_FrontPagePageProperty                            Win32_Publisher12MailMerge
Win32_Language                                         Win32_FrontPageAddIns
Win32_Word12PageSetup                                  Win32_Word12HeaderAndFooter
Win32_ServerExtension                                  Win32_Publisher12ActiveDocumentNoTable
Win32_Word12Addin                                      Win32_WordComAddin
Win32_PowerPoint12PageNumber                           Win32_JetCoreComponents
Win32_Publisher12Fonts                                 Win32_Word12Table
Win32_OutlookAlternateStartupFile                      Win32_Word12Tables
Win32_Access12ComAddins                                Win32_Excel12AlternateStartupFileLoc
Win32_Word12FileConverters                             Win32_Access12StartupFolder
Win32_Word12ParagraphStyle                             Win32_Access12ComAddin
Win32_Excel12StartupFolder                             Win32_PowerPointPresentation
Win32_FrontPageWebProperty                             Win32_Publisher12Table
Win32_Publisher12StartupFolder                         Win32_WebConnectionErrorText
Win32_ExcelSheet                                       Win32_Publisher12Tables
Win32_FrontPageTheme                                   Win32_PowerPoint12ComAddins
Win32_Word12Template                                   Win32_ExcelComAddins
Win32_Access12AlternateStartupFileLoc                  Win32_Word12ActiveDocument
Win32_PublisherSummary                                 Win32_Publisher12DefaultFileLocation
Win32_Word12Field                                      Win32_Publisher12Hyperlinks
Win32_PowerPoint12ComAddin                             Win32_PowerPoint12Hyperlink
Win32_PowerPoint12DefaultFileLoc                       Win32_Publisher12Sections
Win32_OutlookStartupFolder                             Win32_Access12JetComponents
Win32_Word12ActiveDocumentNotable                      Win32_Publisher12CharacterStyle
Win32_Word12Hyperlinks                                 Win32_Word12MailMerge
Win32_Word12FileConverter                              Win32_PowerPoint12Hyperlinks
Win32_FrontPageActivePage                              Win32_Word12Summary
Win32_OleDbProvider                                    Win32_Publisher12PageSetup
Win32_Word12SelectedTable                              Win32_PowerPoint12StartupFolder
Win32_OdbcCoreComponent                                Win32_PowerPoint12PageSetup
Win32_FrontPageSummary                                 Win32_AccessSummary
Win32_Word12Hyperlink                                  Win32_OfficeWatsonLog
Win32_Publisher12Font                                  Win32_WebConnectionErrorMessage
Win32_AccessDatabase                                   Win32_Publisher12Styles
Win32_Publisher12ActiveDocument                        Win32_Word12AlternateStartupFileLocation
Win32_PowerPoint12Fonts                                Win32_Word12Sections
Win32_ExcelComAddin                                    Win32_Excel12DefaultFileLoc
Win32_Word12Fields                                     Win32_ExcelActiveWorkbookNotable
Win32_Publisher12COMAddIn                              Win32_ExcelWorkbook
Win32_OutlookComAddin                                  Win32_PowerPoint12Font
Win32_FrontPageAddIn                                   Win32_ExcelChart
Win32_WebConnectionError                               Win32_Word12Font
Win32_RDOCoreComponents                                Win32_Word12PageNumber
Win32_Publisher12ParagraphStyle                        Win32_Publisher12COMAddIns
Win32_Transport                                        Win32_Access12DefaultFileLoc
Win32_FrontPageThemes                                  Win32_ExcelSummary
Win32_ExcelAddIn                                       Win32_Publisher12AlternateStartupFileLocation
Win32_PowerPoint12SelectedTable

Converting the WMI Date Format

WMI uses special date formats. For example, look at Win32_OperatingSystem objects:

Get-WmiObject Win32_OperatingSystem | Format-List *time*
CurrentTimeZone : 120
LastBootUpTime  : 20111016085609.375199+120
LocalDateTime   : 20111016153922.498000+120

The date and time are represented a sequence of numbers: first the year, then the month, and finally the day. Following this is the time in hours, minutes, and milliseconds, and then the time zone. This is the so-called DMTF standard, which is hard to read. However, you can use ToDateTime() of the ManagementDateTimeConverter .NET class to decipher this cryptic format:

$boottime = (Get-WmiObject win32_OperatingSystem).LastBootUpTime
$boottime
20111016085609.375199+120
$realtime = [System.Management.ManagementDateTimeConverter]::ToDateTime($boottime)
$realtime
Tuesday, October 16, 2011 8:56:09 AM 

Now you can also use standard date and time cmdlets such as New-TimeSpan to calculate the current system uptime:

New-TimeSpan $realtime (Get-Date)
Days              : 0
Hours             : 6
Minutes           : 47
Seconds           : 9
Milliseconds      : 762
Ticks             : 244297628189
TotalDays         : 0.282751884478009
TotalHours        : 6.78604522747222
TotalMinutes      : 407.162713648333
TotalSeconds      : 24429.7628189
TotalMilliseconds : 24429762.8189