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
- Retrieving Information
- Changing System Configuration
- WMI Events
- Using WMI Remotely
- WMI Background Information
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