Use PowerShell to Find Writable WMI Properties

Use PowerShell to Find Writable WMI Properties

  • Comments 4
  • Likes

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

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Nice script, shame about the "Quota Violation" error I get when I run it.

    What can we do about that that?

  • @Neil there are two ways to deal with this. The first is to set $errorActionPreference = "SilentlyContinue" this will hide the error, but not really do anything else. The second one involves raising the quota limit. To do this, you will need to bump up the memory that you allow WMI to use. By default on Windows XP this is 128 MB, on Windows Vista and above it is 512 MB. You will probably want to increase the value of MemoryPerHost. On my Windows 7 machine this value is 536870912 which is equal to 512 MB. Because you set the value in bytes, multiple your new value by 1048576. support.microsoft.com/.../2404366 talks about modifying these values. The thing to keep in mind is that the __ProviderHostQuotaConfiguration WMI class exists in the Root namespace, and not Root\CimV2 which is the default WMI namespace. On Windows XP and Windows Server 2003 WbemTest connects to the Root namespace. On Windows Vista this changed to reflect the default WMI namespace. Hope this helps ... I am glad you like the script.

  • hi you wouldn't happen to know the name of program used in the two first screenshots. do you? It will help me a lot if I had that program. I'll also leave a message at your latest blog post. it's really urgent that I get that program ASAP. Email: mohsentux@live.com

  • @Anonymous - the program name is clearly given in the text.