Hey, Scripting Guy! Can Windows PowerShell Call WMI Methods?

Hey, Scripting Guy! Can Windows PowerShell Call WMI Methods?

  • Comments 4
  • Likes

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I have seen a number of methods listed for WMI classes on MSDN, but when I try to use them in Windows PowerShell, they do not work. I am wondering what the secret is to making these things actually do something. I assume they are not really broken because I have VBScripts that I downloaded from the Script Center Script Repository that work just fine. So it must be a Windows PowerShell issue. Can Windows PowerShell call WMI methods?

-- DS

Hey, Scripting Guy! AnswerHello DS,

Microsoft Scripting Guy Ed Wilson here. I am feeling much better now that I have had a sufficient amount of sleep. The jet lag from my trip to Seattle, Washington, in the United States for the Microsoft TechReady conference is over. As one late twentieth century American philosopher once stated, "I feel good." I have my little blue tea pot with some nice Earl Grey tea and an ANZAC biscuit. My friend Brett in Sydney, Australia, sent a couple of packages of ANZAC biscuits and Tim Tams to me while I was in Seattle by way of another friend (Hemant) who was also attending the TechReady conference, which was good because I had run out of both. Because I now have a stash of ANZAC biscuits, I am sipping tea, munching an ANZAC biscuit, and listening to James Brown on my Zune. Yes, it is good to be home.

DS, short answer: Yes, Windows PowerShell can call WMI methods. As an example, on Windows Server 2003 and later there is a really cool WMI class named Win32_Volume. The reason I love this WMI class is because of the methods. The properties are easy to obtain by using the Get-WmiObject cmdlet. (One thing that is cool is the system property __Property_Count. This tells us there are 44 properties on the Win32_Volume WMI class.) This is seen here:

PS C:\> Get-WmiObject -Class win32_volume


__GENUS                      : 2
__CLASS                      : Win32_Volume
__SUPERCLASS                 : CIM_StorageVolume
__DYNASTY                    : CIM_ManagedSystemElement
__RELPATH                    : Win32_Volume.DeviceID="\\\\?\\Volume{a281f0f1-45
                               07-11dc-be35-806e6f6e6963}\\"
__PROPERTY_COUNT             : 44
__DERIVATION                 : {CIM_StorageVolume, CIM_StorageExtent, CIM_Logic
                               alDevice, CIM_LogicalElement...}
__SERVER                     : VISTA
__NAMESPACE                  : root\cimv2
__PATH                       : \\VISTA\root\cimv2:Win32_Volume.DeviceID="\\\\?\
                               \Volume{a281f0f1-4507-11dc-be35-806e6f6e6963}\\"
Access                       :
Automount                    : True
Availability                 :
BlockSize                    : 4096
BootVolume                   : True
Capacity                     : 68716326912
Caption                      : C:\
Compressed                   : False
ConfigManagerErrorCode       :
ConfigManagerUserConfig      :
CreationClassName            :
Description                  :
DeviceID                     : \\?\Volume{a281f0f1-4507-11dc-be35-806e6f6e6963}
                               \
DirtyBitSet                  : False
DriveLetter                  : C:
DriveType                    : 3
ErrorCleared                 :
ErrorDescription             :
ErrorMethodology             :
FileSystem                   : NTFS
FreeSpace                    : 51106398208
IndexingEnabled              : False
InstallDate                  :
Label                        :
LastErrorCode                :
MaximumFileNameLength        : 255
Name                         : C:\
NumberOfBlocks               :
PageFilePresent              : True
PNPDeviceID                  :
PowerManagementCapabilities  :
PowerManagementSupported     :
Purpose                      :
QuotasEnabled                : False
QuotasIncomplete             : False
QuotasRebuilding             : False
SerialNumber                 : 4241210807
Status                       :
StatusInfo                   :
SupportsDiskQuotas           : True
SupportsFileBasedCompression : True
SystemCreationClassName      :
SystemName                   : VISTA
SystemVolume                 : True

__GENUS                      : 2
__CLASS                      : Win32_Volume
__SUPERCLASS                 : CIM_StorageVolume
__DYNASTY                    : CIM_ManagedSystemElement
__RELPATH                    : Win32_Volume.DeviceID="\\\\?\\Volume{a281f0f4-45
                               07-11dc-be35-806e6f6e6963}\\"
__PROPERTY_COUNT             : 44
__DERIVATION                 : {CIM_StorageVolume, CIM_StorageExtent, CIM_Logic
                               alDevice, CIM_LogicalElement...}
__SERVER                     : VISTA
__NAMESPACE                  : root\cimv2
__PATH                       : \\VISTA\root\cimv2:Win32_Volume.DeviceID="\\\\?\
                               \Volume{a281f0f4-4507-11dc-be35-806e6f6e6963}\\"
Access                       :
Automount                    : True
Availability                 :
BlockSize                    :
BootVolume                   :
Capacity                     :
Caption                      : D:\
Compressed                   :
ConfigManagerErrorCode       :
ConfigManagerUserConfig      :
CreationClassName            :
Description                  :
DeviceID                     : \\?\Volume{a281f0f4-4507-11dc-be35-806e6f6e6963}
                               \
DirtyBitSet                  :
DriveLetter                  : D:
DriveType                    : 5
ErrorCleared                 :
ErrorDescription             :
ErrorMethodology             :
FileSystem                   :
FreeSpace                    :
IndexingEnabled              :
InstallDate                  :
Label                        :
LastErrorCode                :
MaximumFileNameLength        :
Name                         : D:\
NumberOfBlocks               :
PageFilePresent              :
PNPDeviceID                  :
PowerManagementCapabilities  :
PowerManagementSupported     :
Purpose                      :
QuotasEnabled                :
QuotasIncomplete             :
QuotasRebuilding             :
SerialNumber                 :
Status                       :
StatusInfo                   :
SupportsDiskQuotas           :
SupportsFileBasedCompression :
SystemCreationClassName      :
SystemName                   : VISTA
SystemVolume                 :

One thing you will notice is that not all properties return data. One day, DS, I will show you a really cool way to take care of the missing property value problem (the technique is something I came up with while I was writing the 200 scripts for the Windows 7 Resource Kit), but that is a subject for a future Hey, Scripting Guy! article. The thing that is important to notice here is that there are two instances of Win32_Volumes returned in response to our query. If I were to run this script on my other desktop, I would have six instances of the Win32_Volume class returned. Because there are multiple instances of the Win32_Volume WMI class returned by the Get-WmiObject cmdlet, it means that you cannot directly access the methods. This is in spite of the fact that the Get-Member cmdlet clearly displays them as seen here:
 

PS C:\> Get-WmiObject -Class win32_volume | Get-Member -MemberType method


   TypeName: System.Management.ManagementObject#root\cimv2\Win32_Volume

Name           MemberType Definition
----           ---------- ----------
AddMountPoint  Method     System.Management.ManagementBaseObject AddMountPoi...
Chkdsk         Method     System.Management.ManagementBaseObject Chkdsk(Syst...
Defrag         Method     System.Management.ManagementBaseObject Defrag(Syst...
DefragAnalysis Method     System.Management.ManagementBaseObject DefragAnaly...
Dismount       Method     System.Management.ManagementBaseObject Dismount(Sy...
Format         Method     System.Management.ManagementBaseObject Format(Syst...
Mount          Method     System.Management.ManagementBaseObject Mount()
Reset          Method     System.Management.ManagementBaseObject Reset()
SetPowerState  Method     System.Management.ManagementBaseObject SetPowerSta...

If you attempt to directly access any of the methods, an error will be generated. This is because WMI does not know which volume you wish to work with. This is seen here:
 

PS C:\> (Get-WmiObject -Class win32_volume).defragAnalysis()
Method invocation failed because [System.Object[]] doesn't contain a method nam
ed 'defragAnalysis'.
At line:1 char:51
+ (Get-WmiObject -Class win32_volume).defragAnalysis <<<< ()
    + CategoryInfo          : InvalidOperation: (defragAnalysis:String) [], Ru
   ntimeException
    + FullyQualifiedErrorId : MethodNotFound

PS C:\> $wmi = Get-WmiObject -Class win32_volume
PS C:\> $wmi.DefragAnalysis()
Method invocation failed because [System.Object[]] doesn't contain a method nam
ed 'DefragAnalysis'.
At line:1 char:20
+ $wmi.DefragAnalysis <<<< ()
    + CategoryInfo          : InvalidOperation: (DefragAnalysis:String) [], Ru
   ntimeException
    + FullyQualifiedErrorId : MethodNotFound

To work with the method, you will need to obtain a single instance of the class. There are a couple of ways to do this. You do not have to only have a single instance of the class, but you must be working with a single instance at a time. The easiest way to call the method is to use the Foreach-Object cmdlet to work through the collection of Win32_Volumes. To do this, you use the Get-WmiObject cmdlet to query for all instances of the Win32_Volume, and you use the pipeline to pass the objects to the Foreach-Object cmdlet. Inside the script block for the Foreach-Object cmdlet, you use the $_ automatic variable to refer to the current object on the pipeline. This allows you to call the DefragAnalysis method. This technique is seen here:
 

PS C:\> Get-WmiObject -Class win32_volume | Foreach-Object { $_.DefragAnalysis()
 }


__GENUS           : 2
__CLASS           : __PARAMETERS
__SUPERCLASS      :
__DYNASTY         : __PARAMETERS
__RELPATH         :
__PROPERTY_COUNT  : 3
__DERIVATION      : {}
__SERVER          :
__NAMESPACE       :
__PATH            :
DefragAnalysis    : System.Management.ManagementBaseObject
DefragRecommended : False
ReturnValue       : 0

__GENUS           : 2
__CLASS           : __PARAMETERS
__SUPERCLASS      :
__DYNASTY         : __PARAMETERS
__RELPATH         :
__PROPERTY_COUNT  : 3
__DERIVATION      : {}
__SERVER          :
__NAMESPACE       :
__PATH            :
DefragAnalysis    : System.Management.ManagementBaseObject
DefragRecommended : False
ReturnValue       : 2

Because the Get-WmiObject cmdlet returns a collection of Win32_Volume objects, you can index directly into the collection and call the method directly. After you have indexed into the collection, you have referenced a single item and you are allowed to call methods. Of course, the problem is you may not always know which instance of the object you are referencing. This method is seen here:

PS C:\> $wmi = Get-WmiObject -Class win32_volume
PS C:\> $wmi[0].DefragAnalysis()

__GENUS           : 2
__CLASS           : __PARAMETERS
__SUPERCLASS      :
__DYNASTY         : __PARAMETERS
__RELPATH         :
__PROPERTY_COUNT  : 3
__DERIVATION      : {}
__SERVER          :
__NAMESPACE       :
__PATH            :
DefragAnalysis    : System.Management.ManagementBaseObject
DefragRecommended : False
ReturnValue       : 0

A better way to call the method is to use a WMI query that only returns a single instance of the WMI class. To do this, you use the filter parameter and select the drive letter. Store the Win32_Volume WMI object that is returned in a variable named $wmi. Next you use the single instance of the Win32_Volume WMI class to call the DefragAnalysis method. Store the Win32_DefragAnalysis object that is returned in a variable named $rtn. This is seen here:

PS C:\> $wmi = Get-WmiObject -Class win32_volume -Filter "driveletter = 'c:'"
PS C:\> $rtn = $wmi.DefragAnalysis()

After you have the return object, you can call the DefragAnalysis property and display all the information about the results of the DefragAnalysis. This is seen here:

Image of DefragAnalysis property results

You can easily put the above command into a function, so it will be more readily available. This is seen here.

Get-DefragAnalysisFunction.ps1

Function Get-DefragAnalysis($drive)
{
 $wmi = Get-WmiObject -Class win32_volume -Filter "driveletter = '$drive'"
 $rtn = $wmi.DefragAnalysis()
 $rtn.DefragAnalysis
} #end Get-DefragAnalysis

# *** Entry Point to Script ***
"Getting Defrag analysis of $($env:ComputerName). This may take some time ..."
Get-DefragAnalysis("c:") | Format-List -Property [a-z]*

Well, DS, this concludes our excursion into calling WMI methods. We will continue looking at working with methods tomorrow as WMI Week continues. In the meantime, you can look at our WMI Hub where you will find links to some excellent WMI resources (including a couple of good books from Microsoft Press).  If you want to be the first to know what is happening on the Script Center, follow us on Twitter or on Facebook. If you need assistance with a script, you can post questions to the Official Scripting Guys Forum, or send an e-mail to scripter@microsoft.com. Until tomorrow, keep cool. 
 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Good afternoon Ed,  In this post you mention a method to handle empty properties.  I'm currently looking to get the availability property of the win32_DiskDrive class to return but it's always empty.  Any ideas?

  • @Luke Campbell Two thoughts: make sure you run the command with admin rights because SOME WMI properties do not display if you do not have admin rights. Also keep in mind that some WMI properties return no information at all. In addition, some WMI properties return information on Windows 7 but not on Windows XP, and at times even vice versa. On my Windows 8 laptop, running PowerShell with admin rights, availability does not display for the Win32_DiskDrive class. However, on Windows 8 the Get-Disk function does display OperationalStatus which is probably what you are seeking.

  • Unfortunately I'm working with Windows Server 2008 R2 and am querying the class remotely using an admin account.  Hmm, looking for methods to check if a disk is offline in a clustered scenario.

  • Hi, in the steps you gave, only properties were called I suppose. Can you please guide how to call methods as well?

    Chaitanya.