Summary: Use Windows PowerShell to gather all implemented methods and writable properties from all WMI namespaces.

Weekend Scripter

Microsoft Scripting Guy, Ed Wilson, here. It is quiet around here on the weekends. At times, it is extremely quiet. I decided to use the time to make some serious changes to my WMI method and property discovery script I have been working on the previous several days.

On Thursday, I wrote a script that gathers implemented methods from all of the dynamic WMI classes in a single WMI namespace. By default, this WMI namespace is root\cimv2. On Friday, I wrote a script that retrieves all of the writable properties from all of the dynamic WMI classes in a single WMI namespace. On Saturday, I combined these two scripts and added the ability to write to a text file.

Today I thought I would modify yesterday’s script to query all WMI namespaces. Because this can take a rather long time, I also decided to implement a nested progress bar. It is a cool script. It is also rather long; therefore, I uploaded it to the Scripting Guys Script Repository.

The big change involves creating a function that generates a recursive listing of all WMI namespaces on the target computer (by default this is the local computer). A recursive listing is required because of the deeply nested structure that is used by the WMI namespaces. This structure is illustrated in the following graphic.

Image of nested structure

I decided to filter out the root\directory WMI namespace, in addition to all namespaces below this namespace. The reason is because during my testing, it was taking an extremely long time to complete the enumeration of the classes in those namespaces, and in the end, nothing was showing up that was usable.

If you want to add it back, I have added a comment that will help you locate the line to remove. The technique of filtering out a namespace is useful anyway, because you may wish to create custom reports and exclude certain namespaces—therefore, it is all good.

The Get-WmiNamespace function is similar to one I wrote for the Windows 7 Resource Kit. I added the value “SilentlyContinue” for the ErrorAction parameter because you will not always have rights to all WMI namespaces, and I wanted to suppress the errors. The complete text for the Get-WmiNamespace function is shown here:

Function Get-WmiNameSpace

{

 Param(

  $nameSpace = "root",

  $computer = "localhost"

 )

 Get-WmiObject -class __NameSpace -computer $computer `

 -namespace $namespace -ErrorAction "SilentlyContinue" |

 Foreach-Object `

 -Process `

   {

     $subns = Join-Path -Path $_.__namespace -ChildPath $_.name

     #Following line skips the root\directory & root\directory\LDAP namespaces

     if($subns -notmatch 'directory') {$subns}

     $namespaces += $subns + "`r`n"

     Get-WmiNameSpace -namespace $subNS -computer $computer

   }

} #end Get-WmiNameSpace

The entry point to the script sees me setting the value “SilentlyContinue” to the global $ErrorActionPreference variable. I do this to suppress any errors that may occur while running the script. Obviously, when writing the script one wants to see the errors, and indeed most of the time I want to see the errors. Therefore, I set it back to the default value of “Continue” at the bottom of the script.

Next, I set a path for the log file, display a message that states I am gathering WMI namespaces, and I call the Get-WMiNamespace function. After the collection of namespaces is generated, I initialize the $j variable that is used to keep track of my progress through the WMI namespaces. This portion of the script is shown here.

$ErrorActionPreference = "SilentlyContinue"

$ErrorActionPreference = "SilentlyContinue"

$path = "C:\fso\WMiMethodsAndPropertiesInAllNamespaces.txt"

"Collecting WMI Namespaces"

$CollectionOfNamespaces = Get-WmiNameSpace

$j = 0

I use the ForEach statement to walk through the collection of WMI namespaces. I now write to the log file by using the redirection arrow. This first message provides the name of the WMI namespace. Next, I use the Write-Progress cmdlet to track my progress through the WMI namespaces.

For information about using the Write-Progress cmdlet to create a nested progress bar, see the Provide Progress for Your Script with a PowerShell Cmdlet Hey, Scripting Guy! blog. Basic information about the Write-Progress cmdlet appears in the Add a Progress Bar to Your PowerShell Script Hey, Scripting Guy! blog.

This portion of the script is shown here.

Foreach($namespace in $collectionOfNamespaces)

{

 "Checking $namespace" >> $path

 Write-Progress -Activity "Inspecting Properties and Methods" `

  -Status "Checking namespace $($namespace)" `

  -PercentComplete ($j / $CollectionOfNamespaces.Length*100) -Id 1 `

  -ErrorAction "SilentlyContinue"

Now I initialize the $I variable, which is used as a counter to mark progress through the collection of WMI classes. I then retrieve a listing of all the WMI classes in the namespace, and I store the resulting classes in the $classes variable. As I walk through the collection of classes, I use a nested Write-Progress bar to mark my progress through the collection of classes. I then call the Get-WMIClassMethods function and the Get-WmiClassProperties function and clean everything up. This portion of the script is shown here.

$i = 0

$classes = Get-WmiObject -List -Namespace $namespace -EA "SilentlyContinue"

Foreach($class in $classes)

 {

  Write-Progress -Activity "Inspecting Properties and Methods" `

  -Status "Checking $($class.name)" `

  -PercentComplete ($i / $classes.count*100) -ErrorAction "SilentlyContinue" `

  -ParentId 1

  Get-WmiClassMethods -class $class >>$path

  Get-WmiClassProperties -class $class >>$path

  $i++

 } #end foreach class

  $j++

} #end foreach namespace

$ErrorActionPreference = "Continue"

When the script runs, the first thing that appears in the Windows PowerShell ISE display panel (in fact the only thing that appears) is the message that states I am gathering WMI namespaces. This is shown in the following image.

Image of message

After all of the WMI namespaces are gathered, the nested progress bar appears. The top progress bar indicates progress through the namespaces, and the bottom bar indicates the progress through the collection of dynamic WMI classes inside the current namespace. The nested progress bar is shown in the following image.

Image of nested progress bar

When the script completes its run, the implemented WMI methods and writable properties for each class in each namespace appear in the text file that you specified to the $path variable. A copy of my text file is shown in the following image.

Image of text file

That is about all there is to exploring WMI for implemented methods and writable properties. Join me tomorrow when I will talk about using a few of our newly discovered writable properties to make useful configuration changes. It is cool, and I am sure you do not want to miss it.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy