Use PowerShell to Find Writable WMI Properties

Summary: Learn how to use Windows PowerShell to find WMI classes that allow you to change property values.

Hey, Scripting Guy! Question  Hey Scripting Guy! I recently saw a Windows PowerShell script that looked like it actually changed the value of a property. I know that Windows PowerShell methods require you to put things in parentheses, and this script did not have any parentheses. The fact that it used an equal sign (=) makes me think that it was changing a property, but it seems like it should have used a method to make a change. Is this a Windows PowerShell thing, or a WMI thing, or did the script actually not work?

—JE

Hey, Scripting Guy! Answer Hello JE,

Microsoft Scripting Guy, Ed Wilson, here. I appreciate your confidence in me. Without even providing me with the text of a script, you ask me if it will work or not! Dude (or dudette), I have been asked all kinds of wild questions in the past, but never has anyone asked me to tell them if a script will work sight unseen. However, I think I might understand your confusion.

Windows Management Instrumentation (WMI) actually exposes a few properties that are read/write. This means I can actually change things by setting a new value for a property. Although WMI methods show up in a convenient location in the MSDN documentation, and even in the WMI Tester (WbemTest), there is no centralized location for read/write WMI properties. Methods for the Win32_Volume WMI class are shown in the following image.

Image of properties and methods

In the end, if one wishes to find properties that can do things, one has to click them one-by-one. Using wbemtest to find a read/write property entails double-clicking every single property in the property list of Properties section. When the Property Editor appears, if the property has the write Qualifier (in the Qualifiers section) the property is read/write. The Property Editor for the DriveLetter property of the Win32_Volume WMI class is shown in the following image. As you can see, this property is writable.

Image of Property Editor

The only problem with this approach is that the Win32_Volume WMI class has 44 regular properties and 10 system properties. I discovered this by using the following code.

PS C:\Users\ed.NWTRADERS> gwmi win32_volume -Filter “driveletter = ‘c:'” | select -ExpandProperty properties | measure-object

Count : 44

Average :

Sum :

Maximum :

Minimum :

Property :

PS C:\Users\ed.NWTRADERS> gwmi win32_volume -Filter “driveletter = ‘c:'” | select systemproperties | measure-object

Count : 1

Average :

Sum :

Maximum :

Minimum :

Property :

I decided to fix this situation by writing a Get-WmiClassProperties.ps1 script that will retrieve all of the read/write WMI properties from all WMI classes in a particular WMI namespace. The complete Get-WmiClassProperties.ps1 script is similar to the Get-WmiClassMethods.ps1 script from yesterday’s Hey Scripting Guy! blog.

The complete Get-WmiClassMethods.ps1 is shown here. For ease of copying, the complete script is uploaded to the Scripting Guys Script Repository.

Get-WmiClassMethods.ps1

# —————————————————————————–

# Script: Get-WmiClassProperties.ps1

# Author: ed wilson, msft

# Date: 03/08/2011 12:46:15

# Keywords: Scripting Techniques, WMI

# comments: Gets dynamic WMI classes that have methods marked with the implemented

# qualifier

# HSG-3-11-11

# —————————————————————————–

function New-Underline

{

<#

.Synopsis

 Creates an underline the length of the input string

.Example

 New-Underline -strIN “Hello world”

.Example

 New-Underline -strIn “Morgen welt” -char “-” -sColor “blue” -uColor “yellow”

.Example

 “this is a string” | New-Underline

.Notes

 NAME:

 AUTHOR: Ed Wilson

 LASTEDIT: 5/20/2009

 KEYWORDS:

.Link

 Http://www.ScriptingGuys.com

#>

[CmdletBinding()]

param(

      [Parameter(Mandatory = $true,Position = 0,valueFromPipeline=$true)]

      [string]

      $strIN,

      [string]

      $char = “=”,

      [string]

      $sColor = “Green”,

      [string]

      $uColor = “darkGreen”,

      [switch]

      $pipe

 ) #end param

 $strLine= $char * $strIn.length

 if(-not $pipe)

  {

   Write-Host -ForegroundColor $sColor $strIN

   Write-Host -ForegroundColor $uColor $strLine

  }

  Else

  {

  $strIn

  $strLine

  }

} #end new-underline function

 

Function Get-WmiClassProperties

{

 Param(

   [string]$namespace = “root\cimv2”,

   [string]$computer = “.”

)

 $abstract = $false

 $property = $null

 $classes = Get-WmiObject -List -Namespace $namespace

 Foreach($class in $classes)

 {

  Foreach($q in $class.Qualifiers)

   { if ($q.name -eq ‘Abstract’) {$abstract = $true} }

  If(!$abstract)

    {

     Foreach($p in $class.Properties)

      {

       Foreach($q in $p.qualifiers)

        {

         if($q.name -match “write”)

          {

            $property += $p.name + “`r`n”

          } #end if name

        } #end foreach q

      } #end foreach p

      if($property) {New-Underline $class.name}

      $property

    } #end if not abstract

  $abstract = $false

  $property = $null

 } #end foreach class

} #end function Get-WmiClassProperties

 

# *** Entry Point to Script ***

Get-WmiClassProperties

The script begins by creating the New-Underline function that has been used in several scripts that appear in the Hey Scripting Guy! blog.

The Get-WmiClassProperties function begins by creating a couple of parameters, initializing a couple of variables, and obtaining a collection of all the WMI classes in a particular WMI namespace. This portion of the script is shown here.

Function Get-WmiClassProperties

{

Param(

[string]$namespace = “root\cimv2”,

[string]$computer = “.”

)

$abstract = $false

$property = $null

$classes = Get-WmiObject -List -Namespace $namespace

Next, the function uses the Foreach keyword to walk through the collection of classes. It checks the class qualifiers collection to see if one of the qualifiers is abstract. If a WMI class is an abstract, it should not be queried directly. This portion of the script is shown here.

Foreach($class in $classes)

{

Foreach($q in $class.Qualifiers)

{ if ($q.name -eq ‘Abstract’) {$abstract = $true} }

After a WMI class is determined to not be an abstract class, the properties collection of the WMI class is retrieved, and each of the properties qualifiers are examined to see if the write qualifier appears. This portion of the script is shown here.

If(!$abstract)

{

Foreach($p in $class.Properties)

{

Foreach($q in $p.qualifiers)

{

if($q.name -match “write”)

I add each writable property name to the $property variable, and add a return and a new line character at the end of each property name. Next I call the New-Underline function to underline the name of WMI classes that have at least one writable WMI property. After that I list each writable property under the name of the WMI class, reinitialize a couple of variables, end the function, and call the script. This portion of the script is shown here.

{

$property += $p.name + “`r`n”

} #end if name

} #end foreach q

} #end foreach p

if($property) {New-Underline $class.name}

$property

} #end if not abstract

$abstract = $false

$property = $null

} #end foreach class

} #end function Get-WmiClassProperties

# *** Entry Point to Script ***

Get-WmiClassProperties

When the script run, it produces a listing similar to the one in the following image.

Image of command output

JE, that is all there is to finding WMI class properties that can actually do things. I invite you to join me tomorrow for the Weekend Scripter, when I will begin to make a couple of improvements to these exploratory scripts—it will be cool!

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