Use the Set-WmiInstance PowerShell Cmdlet to Ease Configuration

Use the Set-WmiInstance PowerShell Cmdlet to Ease Configuration

  • Comments 4
  • Likes

Summary: Learn how to use the Set-WmiInstance Windows PowerShell cmdlet to ease configuration of computers.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I was using the Get-Command cmdlet to look at what things I can do with Windows PowerShell, and I noticed a cmdlet called Set-WmiInstance. I looked at the help, but I don’t get it. What is the big deal?

—BL

 

Hey, Scripting Guy! AnswerHello BL,

Microsoft Scripting Guy Ed Wilson here. Well, the Scripting Wife and I have had a lot of fun in Montreal this week. In a few days, we will be leaving and heading home. The Windows PowerShell class I have been teaching this week has been great, and the students have asked many good questions. In addition, they have given me many ideas for Hey, Scripting Guy! Posts for the future. These questions and ideas usually take the shape of, I am trying to do such and such, but I am having a hard time finding out what I need to do.

BL, the Set-WmiInstance cmdlet is cool, but using it can be a bit complicated. The class parameter sets a property directly on a WMI class. Unfortunately, this works only on singleton WMI classes, of which there are very few. The one singleton class used by network administrators is Win32_Operatingsystem, but unfortunately, it does not work with the class parameter. Therefore, I only use the Set-WmiInstance cmdlet with the path parameter. The trick to using the Set-WmiInstance class with the path parameter is to know what a WMI path actually is and how to retrieve the WMI path for a WMI instance of a class.

Note   In the help files, the example uses the Win32_WMISetting, and it changes the logginglevel property. This works on Windows Server 2003 and earlier, but beginning with Windows Vista, WMI uses ETL logs and does not use this legacy parameter.

One of the good things about working with a singleton class is that the path to the class is easy. The path is the WMI class name equals the @ symbol. This translates into syntax such as that shown here:

WMISingleTonClass=@

When using the Set-WmiInstance on a WMI class, the property to be set uses a hash table as it passes to the arguments parameter. The pairs are the property name and the value to assign to the property name. An example of this syntax is shown here:

@{propertyName=Value}

To assign a new description to the Win32_OperatingSystem singleton class, I perform the following steps (these steps require administrator rights on the target computer):

  1. I use the Set-WmiInstance class
  2. I supply the path to the Win32_OperatingSystem class to the path parameter
  3. I create a hash table using the WMI property name and the value to update the property with

The following command illustrates this technique:

Set-WmiInstance -Path win32_operatingsystem=@ -argument @{description="iammred"}

If I did not have the Set-WmiInstance cmdlet, I would need to use several steps to set the Operating System description property. The steps required to assign a new value to the description property of the Win32_OperatingSystem class are shown here:

  1. Use the Get-WmiObject cmdlet to retrieve an instance of the Win32_Operatingsystem WMI class.
  2. Store the returned management object in a variable.
  3. Assign a new value for the description property.
  4. Call the put method to write the information back to WMI.

The following commands illustrate this technique (the commands must run with elevated permissions):

$os = Get-WmiObject –class win32_operatingsystem

$os.Description = "MyNewDescription"

$os.put()

The situation changes a bit when working with a WMI class that is not a singleton. For example, if I query the Win32_logicalDrive WMI class on my laptop, three instances of the class appear. If I limit the results to only fixed local disks (drivetype = 3), I have two instances of the WMI class. The commands and associated output are shown in the following figure.

Image of commands and associated output

To use the path parameter of the Set-WmiInstance cmdlet requires the path to a specific instance of the WMI class. The following WMI command returns the name of each logical disk and the path to each fixed logical disk.

PS C:\> Get-WmiObject -Class win32_logicaldisk -Filter {drivetype=3} | select name, __path

 

name                                                        __PATH

C:                                                          \\MRED\root\cimv2:Win32_LogicalDisk.DeviceID="C:"

Q:                                                          \\MRED\root\cimv2:Win32_LogicalDisk.DeviceID="Q:"

 

The important port to focus on right now is the result of the query that returns the __path property. The WMI path represented here comprises five parts. The parts in the __Path are shown in the following table.

 

Computer

Namespace

Class

Key Property

Value

\\MRED

root\cimv2

Win32_LogicalDisk

DeviceID

C:

 

If I want to change the Volumename on the C: drive, I use the Set-WmiInstance cmdlet as shown here (this command must run with elevated rights):

Set-WmiInstance -Path '\\MRED\root\cimv2:Win32_LogicalDisk.DeviceID="C:"' -argument @{VolumeName="newlabel"}

The command and associated output are shown in the following figure.

 Image of command and associated output

Now, if I were to change the volume name using the Get-WmiObject cmdlet, I would use the syntax that is shown here:

$disk = Get-WmiObject -Class win32_logicaldisk -Filter "deviceID='c:'"

$disk.VolumeName = "mycustomlabel"

$disk.Put()

In light of the long required path for the Set-WmiInstance command, it might appear the previous Get-WmiObject cmdlet exposes the property modification capability easier. It is possible to combine the best of both worlds. I use the Get-WmiObject cmdlet to retrieve the __Path property to the C: drive, and I store it in the $path variable. I then use that path with the Set-WmiInstance cmdlet. The resultant command is two lines instead of the three lines required for the other method.

The command to combine the two techniques is shown here:

$path = (Get-WmiObject -Class win32_logicaldisk -Filter "deviceID='c:'").__path

Set-WmiInstance -Path $path -argument @{VolumeName="test"}

 

In the following figure, the first line illustrates the technique of obtaining the __path directly from the Get-WmiObject cmdlet. The second line displays the path. The third line stores the path in the $path variable, and the fourth line is the Set-WMiInstance command.

Image of commands

Well, BL, that is all there is to using the Set-WmiInstance cmdlet. I hope you found the discussion helpful. To everyone who has tuned in; I invite you to join me tomorrow.  

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
  • Hi Ed,

    it's good to know, that there are cmdlets I never heard of ... so let's learn something new everyday! :-)

    Well, at first sight, I would judge: this is a cmdlet that we can forget about, if we know how to use

    Get-WmiObject and how we can 'Put' a changed value to work ... that's enought!

    I can't see any advantages in using Set-WmiInstance over Get-WmiObject if I would usually have to call "gwmi" anyway to get the exact name to the path required by Set-WmiInstance! What's the deal then?

    Maybe Set-WmiInstance can do other things that can't be done with "gwmi" ... but for the purpose of changing values, I can't see any advantages ...

    Maybe I got it wrong ... but "gwmi" is still my favorite WMI Cmdlet :-)))

    Klaus.

  • Hi Klaus,

    I think one advantage of Set-WmiInstance (and Invoke-WmiMethod) is its support of pipeline processing.

     gwmi win32_networkadapter -filter "NetConnectionID='Local Area Connection'" | swmi -Arguments @{NetConnectionID="LAN" }

     gwmi win32_volume -filter "DriveType=3" | iwmi -Name defrag

    Of course, don't try the later one if there is a SSD drive. :)

    Chris

  • Hi Ed and Chris

    This is timely- I am re-IPing a site that contains a secondary DNS and WINS server. I can use gwmi to retreive enabled network adaptors to identify machines using this address:

    gwmi -computer $($Server.name) -Class Win32_NetworkAdapterConfiguration | Where-Object {$_.IPEnabled -eq 'True'} | `

    Select IPAddress, MACAddress, DNSServerSearchOrder, WINSPrimaryServer, WINSSecondaryServer

    but how should this pipe to find-and-replace the IP so that 10.x.x.x can be changed to 10.y.y.y, and then this piped to SWMI?

    Is this even possible?

  • To answer my own question, I have discovered that the simplest way to change the IP settings is to use the methods provided with the gwmi object, namely $_.SetDNSServerSearchOrder() and $_.SetWINSServer() etc.

    So my final code is something like:

    $ServerAdapters = Get-WmiObject -ComputerName $ServerName -Class Win32_NetworkAdapterConfiguration | Where-Object {$_.IPEnabled -eq 'True'}

    Foreach ($NIC in $ServerAdapters)

    {

    $DNSServerSearchOrder = $NIC.DNSServerSearchOrder | Foreach-Object {$_ -replace $OldIP, $NewIP}

    $NIC.SetDNSServerSearchOrder($DNSServerSearchOrder)

    }

    Hope this helps someone...