Chapter 28. Windows Management Instrumentation

Introduction

Windows Management Instrumentation (WMI) has long been a core management feature in Windows. It offers amazing breadth, wide reach, and ubiquitous remoting.

2 comments

  1. David "Makovec" Moravec Posted 17 days and 23 hours ago

    I am reviewing this chapter as my first.

  2. Richard Siddaway Posted 10 days and 22 hours ago

    Also reviewing

Add a comment

What WMI lacked in the past, though, was a good way to get to it. Graphically, the wbemtest.exe utility lets you experiment with WMI, its namespaces, and classes. It truly is a testing tool, though, as its complex user interface makes it impractical to use for most scenarios:

2 comments

  1. Aleksandar Nikolic Posted 15 days and 21 hours ago

    its compex user interface --> its complex user interface

  2. Richard Siddaway Posted 10 days and 22 hours ago

    What about PowerGUI and MoW's WMIExplorer

Add a comment

Figure 28.1. Using wbemtest.exe to retrieve a Win32_Process

Using wbemtest.exe to retrieve a Win32_Process


A more user-friendly alternative is the wmic.exe command-line tool. The wmic tool lets you interactively query WMI—but more importantly automate its behavior. As with PowerShell, results within wmic retain a great deal of their structured information and let you write fairly detailed queries:

1 comment

  1. David "Makovec" Moravec Posted 17 days and 23 hours ago

    I don't think wmic is more user-friendly. It's more practical, admin oriented, valuable, but the grammar is hard to catch for most of people I know. Would rather see: "A command-line option for querying WMI is wmic" - or something similar.

Add a comment

PS > WMIC logicaldisk WHERE drivetype=3 `
>>     GET "name,freespace,SystemName,FileSystem,Size"
>>
FileSystem  FreeSpace    Name  Size         SystemName
NTFS        10587656192  C:    34357637120  LEEHOLMES1C23

The language is limited, however, and all of the data's structure is lost once WMIC converts its output to text.

By far, the most popular user interface for WMI has been VBScript, the administrator's traditional scripting language. VBScript offers much richer language facilities than WMIC, and retains WMI's structured data for the entire duration of your script. VBScript has its own class of usability difficulties, however. For example, generating a report of the processes running on a computer often ends up looking like this:

2 comments

  1. Aleksandar Nikolic Posted 15 days and 21 hours ago

    VBScript has its own class of usability difficulties, however. --> However, VBScript has its own class of usability difficulties.

  2. Richard Siddaway Posted 10 days and 22 hours ago

    Explicitly state that VBScript doesn't have a command line element like PowerShell?

Add a comment

strComputer = "atl-dc-01"
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" _
    & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process")
For Each objProcess in colProcessList
    Wscript.Echo "Process: " & objProcess.Name 
    Wscript.Echo "Process ID: " & objProcess.ProcessID 
    Wscript.Echo "Thread Count: " & objProcess.ThreadCount 
    Wscript.Echo "Page File Size: " _
        & objProcess.PageFileUsage 
    Wscript.Echo "Page Faults: " _
        & objProcess.PageFaults 
    Wscript.Echo "Working Set Size: " _
        & objProcess.WorkingSetSize 
Next

It also requires that you write an entire script, and offers no light-weight interactive experience. The Microsoft Scripting Guys' Scriptomatic tool helps make it easier to create many of these mundane scripts, but still doesn't address one-off queries.

Enter PowerShell.

PowerShell elevates WMI to a first-class citizen for both ad-hoc, and structured queries. Since most of the template VBScript for dealing with WMI instances ends up being used to display the results, PowerShell eliminates this step completely. The PowerShell equivalent of the above VBScript is simply:

Get-WmiObject Win32_Process -Computer atl-dc-01

Or, if you want a subset of properties:

Get-WmiObject Win32_Process | Select Name,ProcessId,ThreadCount

By providing a deep and user-friendly integration with WMI, PowerShell puts a great deal of functionality at the fingertips of every administrator.

1 comment

  1. Richard Siddaway Posted 10 days and 22 hours ago

    Is it worth mentioning that Windows featuresrolesapplications such as DNS, IIS and SQL Server add extra functionality to WMI

    Also what about mentioning WMI on 64bit systems is everything the same?

Add a comment

Access Windows Management Instrumentation Data

Problem

You want to work with data and functionality provided by the WMI facilities in Windows.

Solution

To retrieve all instances of a WMI class, use the Get-WmiObject cmdlet:

1 comment

  1. Richard Siddaway Posted 10 days and 22 hours ago

    No mention of Set-WMiInstance

Add a comment

Get-WmiObject -ComputerName Computer -Class Win32_Bios

To retrieve specific instances of a WMI class, using a WMI filter, supply an argument to the –Filter parameter of the Get-WmiObject cmdlet. This is the WHERE clause of a WQL statement, but without the WHERE keyword:

1 comment

  1. Richard Siddaway Posted 10 days and 22 hours ago

    Relationship of Get-WmiObject filter to WQL should be mentioned

Add a comment

Get-WmiObject Win32_Service -Filter "StartMode = 'Auto'"

To retrieve instances of a WMI class using WMI's WQL language, use the [WmiSearcher] type shortcut:

$query = [WmiSearcher] "SELECT * FROM Win32_Service WHERE StartMode = 'Auto'"
$query.Get()

To retrieve a specific instance of a WMI class using a WMI filter, use the [Wmi] type shortcut:

[Wmi] 'Win32_Service.Name="winmgmt"'

To retrieve a property of a WMI instance, access that property as you would access a .NET property:

$service = [Wmi] 'Win32_Service.Name="winmgmt"'
$service.StartMode

To invoke a method on a WMI instance, invoke that method as you would invoke a .NET method:

$service = [Wmi] 'Win32_Service.Name="winmgmt"'
$service.ChangeStartMode("Manual")
$service.ChangeStartMode("Automatic")

To invoke a method on a WMI class, use the Invoke-WmiMethod cmdlet. Alternatively, use the [WmiClass] type shortcut to access that WMI class. Then, invoke that method as you would invoke a .NET method:

Invoke-WmiMethod Win32_Process Create notepad

$class = [WmiClass] "Win32_Process"
$class.Create("Notepad")

To retrieve a WMI class from a specific namespace, use its fully-qualified name along with the [WmiClass] type shortcut:

[WmiClass] "\\COMPUTER\Root\Cimv2:Win32_Process"

Discussion

Working with WMI has long been a staple of managing Windows systems—especially systems that are part of corporate domains or enterprises. WMI supports a huge amount of Windows management tasks, albeit not in a very user-friendly way.

Traditionally, administrators required either VBScript or the WMIC command-line tool to access and manage these systems through WMI. While powerful and useful, these techniques still provided plenty of opportunities for improvement. VBScript lacks support for an ad hoc investigative approach, and WMIC fails to provide (or take advantage of) knowledge that applies to anything outside WMIC.

In comparison, PowerShell lets you work with WMI just like you work with the rest of the shell. WMI instances provide methods and properties, and you work with them the same way you work with methods and properties of other objects in PowerShell.

Not only does PowerShell make working with WMI instances and classes easy once you have them, but it also provides a clean way to access them in the first place. For most tasks, you need only to use the simple [Wmi], [WmiClass], or [WmiSearcher] syntax as shown in the solution.

Along with WMI's huge scope, though, comes a related problem: finding the WMI class that accomplishes your task. To assist you in learning what WMI classes are available, Appendix G, WMI Reference provides a helpful listing of the most common ones. For a script that helps you search for WMI classes by name, description, property name, or property description, see the section called “Program: Search for WMI Classes”.

2 comments

  1. Aleksandar Nikolic Posted 15 days and 20 hours ago

    Appendix G, WMI Reference --> Appendix G. WMI Reference

  2. Lee Holmes Posted 14 days and 16 hours ago

    Thanks. The text for the hyperlinks is automatically generated and follows the official O'Reilly style.

Add a comment

Some advanced WMI tasks require that you enable your security privileges or adjust the packet privacy settings used in your request. All of PowerShell's WMI cmdlets support these options through built-in parameters.

When you want to access a specific WMI instance with the [Wmi] accelerator, you might at first struggle to determine what properties WMI lets you search on. These properties are called key properties on the class. For a script that lists these key properties, see the section called “Program: Determine Properties Available to WMI Filters”.

For more information about the Get-WmiObject cmdlet, type Get-Help Get-WmiObject.

1 comment

  1. David "Makovec" Moravec Posted 17 days and 23 hours ago

    For more information about cmdlet used for getting data from WMI - Get-WmiObject - type Get-Help Get-WmiObject.

Add a comment

Modify the Properties of a WMI Instance

Problem

You want to modify the properties of a WMI instance.

Solution

Use the Set-WmiInstance cmdlet:

PS > $bootVolume = Get-WmiObject Win32_LogicalDisk |
>>     Where-Object { $_.DeviceID -eq 'C:' }
>>
PS > $bootVolume

DeviceID     : C:
DriveType    : 3
ProviderName :
FreeSpace    : 10587656192
Size         : 34357637120
VolumeName   : Boot Volume

PS > $bootVolume | Set-WmiInstance -Arguments @{ VolumeName = 'Vista' }

DeviceID     : C:
DriveType    : 3
ProviderName :
FreeSpace    : 10587656192
Size         : 34357637120
VolumeName   : Vista

Discussion

While you can assign new property values to the objects output by Get-WmiObject, changes you make ultimately are not reflected in the permanent system state. For example:

PS > $bootVolume = Get-WmiObject Win32_LogicalDisk |
>>     Where-Object { $_.DeviceID -eq 'C:' }
>>
PS > $bootVolume

DeviceID     : C:
DriveType    : 3
ProviderName :
FreeSpace    : 10587656192
Size         : 34357637120
VolumeName   : Vista

PS > $bootVolume.VolumeName = "Boot Volume"

PS > Get-WmiObject Win32_LogicalDisk |
>>     Where-Object { $_.DeviceID -eq 'C:' }
>>

DeviceID     : C:
DriveType    : 3
ProviderName :
FreeSpace    : 10587652096
Size         : 34357637120
VolumeName   : Vista

Instead, the Set-WmiInstance cmdlet lets you permanently modify values of WMI instances. While the Set-WmiInstance cmdlet supports WMI instances as pipeline input, you can also pass the fully-qualified path to the -Path parameter:

Set-WmiInstance -Path "Win32_LogicalDisk.DeviceID='C:'" `
    -Argument @{ VolumeName="Vista" }

To determine which properties can be modified on an instance, you need to investigate the WMI class that defines it. Each WMI class has a Properties collection, and each property has a Qualifiers collection. If Write is one of the qualifiers, then that property is writeable:

PS > [WmiClass] "Win32_LogicalDisk" | Select -Expand Properties

(...)
Name       : VolumeName
Value      :
Type       : String
IsLocal    : True
IsArray    : False
Origin     : Win32_LogicalDisk
Qualifiers : {CIMTYPE, MappingStrings, read, write}

Name       : VolumeSerialNumber
Value      :
Type       : String
IsLocal    : True
IsArray    : False
Origin     : Win32_LogicalDisk
Qualifiers : {CIMTYPE, MappingStrings, read}
(...)

To automatically see all writeable classes in the ROOT\CIMV2 namespace, simply run this snippet of PowerShell script:

$writeableProperties = Get-WmiObject -List -Recurse |
    Select -Expand Properties |
    Where-Object { $_ | Select -Expand Qualifiers |
        Where-Object { $_.Name -eq "Write" } } | Select Origin,Name

Like all other WMI-related cmdlets, the Set-WmiInstance cmdlet lets you configure impersonation, authentication, and privilege restrictions. For more information about working with WMI classes, see the section called “Access Windows Management Instrumentation Data”.

See Also

Invoke a Method on a WMI Class

Problem

You want to invoke a method supported by a a WMI class.

1 comment

  1. David "Makovec" Moravec Posted 17 days and 22 hours ago

    typo: "a a"

Add a comment

Solution

Use the Invoke-WmiMethod cmdlet:

PS > Invoke-WmiMethod -Class Win32_Process -Name Create -Args notepad.exe
(notepad starts)

__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     :
__DYNASTY        : __PARAMETERS
__RELPATH        :
__PROPERTY_COUNT : 2
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
ProcessId        : 3644
ReturnValue      : 0

Discussion

As with .NET types, WMI classes describe the functionality and features of a related set of items. For example, the Win32_Process class describes the features and behavior of an entity called an operating system process. When WMI returns information about a specific operating system process, that is called an instance.

1 comment

  1. Aleksandar Nikolic Posted 15 days and 20 hours ago

    WMI, classes --> WMI classes

Add a comment

As with static methods on .NET types, many WMI classes offer methods that relate broadly to the entity they try to represent. For example, the Win32_Process class defines methods to start processes, stop them, and more. To invoke any of these methods, call the Invoke-WmiMethod cmdlet.

While you may already know the method you want to call, PowerShell also offers a way to see the methods exposed by WMI classes on your system. Each WMI class has a Methods collection, and reviewing that collection lists all methods supported by that class. The following snippet lists all methods supported by all classes in the ROOT\CIMV2 namespace:

Get-WmiObject -List -Recurse | Select -Expand Methods | Select Origin,Name

Like all other WMI-related cmdlets, the Invoke-WmiIMethod cmdlet lets you configure impersonation, authentication, and privilege restrictions.

In addition to the Invoke-WmiMethod cmdlet, the [WmiClass] type shortcut also lets you refer to a WMI class and invoke its methods:

$processClass = [WmiClass] "Win32_Process"
$processClass.Create("notepad.exe")

This method, however, does not easily support customization of impersonation, authentication, or privilege restrictions.

1 comment

  1. Richard Siddaway Posted 10 days and 22 hours ago

    Is there an example of using impersonation, authentication or privilege restrictions

Add a comment

For more information about working with WMI classes, see the section called “Access Windows Management Instrumentation Data”.

See Also

Program: Determine Properties Available to WMI Filters

When you want to access a specific WMI instance with PowerShell's [Wmi] type shortcut, you might at first struggle to determine what properties WMI lets you search on. These properties are called key properties on the class. Example 28.1, “Get-WmiClassKeyProperty.ps1” gets all the properties you may use in a WMI filter for a given class.

Example 28.1. Get-WmiClassKeyProperty.ps1

##############################################################################

param( [WmiClass] $wmiClass )

foreach($currentProperty in $wmiClass.Properties)
{
    foreach($qualifier in $currentProperty.Qualifiers)
    {
        if($qualifier.Name -eq "Key")
        {
            $currentProperty.Name
        }
    }
}

For more information about running scripts, see the section called “Run Programs, Scripts, and Existing Tools”.

Program: Search for WMI Classes

Along with WMI's huge scope comes a related problem: finding the WMI class that accomplishes your task. To help you learn what WMI classes are available, Appendix G, WMI Reference provides a helpful listing of the most common ones. If you want to dig a little deeper, though, Example 28.2, “Search-WmiNamespace.ps1” lets you search for WMI classes by name, description, property name, or property description.

Example 28.2. Search-WmiNamespace.ps1

##############################################################################

param(
    [string] $pattern = $(throw "Please specify a search pattern."),
    [switch] $detailed,
    [switch] $full,

    [string[]] $matchOptions = ("ClassName","ClassDescription")
)

function New-WmiMatch
{
    param( $matchType, $className, $propertyName, $line )

    $wmiMatch = New-Object PsObject -Property @{
        MatchType = $matchType;
        ClassName = $className;
        PropertyName = $propertyName;
        Line = $line
    }

    $wmiMatch
}

if($detailed)
{
    $matchOptions = "ClassName","ClassDescription","PropertyName"
}

if($full)
{
    $matchOptions = 
        "ClassName","ClassDescription","PropertyName","PropertyDescription"
}

foreach($matchOption in $matchOptions)
{
    $fullMatchOptions =
        "ClassName","ClassDescription","PropertyName","PropertyDescription"

    if($fullMatchOptions -notcontains $matchOption)
    {
        $error = "Cannot convert value {0} to a match option. " +
                 "Specify one of the following values and try again. " +
                 "The possible values are ""{1}""."
        $ofs = ", "
        throw ($error -f $matchOption, ([string] $fullMatchOptions))
    }
}

foreach($class in Get-WmiObject -List -Rec)
{
    $managementOptions = New-Object System.Management.ObjectGetOptions
    $managementOptions.UseAmendedQualifiers = $true
    $managementClass = 
        New-Object Management.ManagementClass $class.Name,$managementOptions
    
    if($matchOptions -contains "ClassName")
    {
        if($managementClass.Name -match $pattern)
        {
            New-WmiMatch "ClassName" `
                $managementClass.Name $null $managementClass.__PATH
        }
    }

    if($matchOptions -contains "ClassDescription")
    {
        $description = 
            $managementClass.Qualifiers | 
                foreach { if($_.Name -eq "Description") { $_.Value } }
        if($description -match $pattern)
        {
            New-WmiMatch "ClassDescription" `
                $managementClass.Name $null $description
        }
    }

    foreach($property in $managementClass.Properties)
    {
        if($matchOptions -contains "PropertyName")
        {
            if($property.Name -match $pattern)
            {
                New-WmiMatch "PropertyName" `
                    $managementClass.Name $property.Name $property.Name
            }
        }

        if($matchOptions -contains "PropertyDescription")
        {
            $propertyDescription = 
                $property.Qualifiers | 
                    foreach { if($_.Name -eq "Description") { $_.Value } }
            if($propertyDescription -match $pattern)
            {
                New-WmiMatch "PropertyDescription" `
                    $managementClass.Name $property.Name $propertyDescription
            }
        }
    }
}

2 comments

  1. Aleksandar Nikolic Posted 15 days and 20 hours ago

    New Property parameter (-Property ]) might be used as well:

    $ht = @{

      MatchType=$matchType;
    
      ClassName=$className;
    
      PropertyName=$propertyName;
    
      Line=$line
    
      }
    

    $wmiMatch = New-Object PsObject -Property $ht

    $wmiMatch

  2. Aleksandar Nikolic Posted 15 days and 20 hours ago

    Full name of the Recurse parameter:

    foreach($class in Get-WmiObject -List -Rec) --> foreach($class in Get-WmiObject -List -Recurse)

Add a comment


For more information about running scripts, see the section called “Run Programs, Scripts, and Existing Tools”.

Use .NET to Perform Advanced WMI Tasks

Problem

You want to work with advanced features of WMI, but PowerShell's access (through the [Wmi], [WmiClass], and [WmiSearcher] accelerators) does not directly support them.

Solution

To interact with advanced features of WMI objects, access their methods and properties.

1 comment

  1. Aleksandar Nikolic Posted 15 days and 20 hours ago

    psbase property is not used in a code in the solution. psbase property is not needed anymore in PowerShell version two.

Add a comment

Advanced instance features

To get WMI instances related to a given instance (its associators), call the GetRelated() method:

$instance = [Wmi] 'Win32_Service.Name="winmgmt"'
$instance.GetRelated()

1 comment

  1. Richard Siddaway Posted 10 days and 22 hours ago

    Is this the same as ASSOCIATORS?

Add a comment

To change advanced scope options, access the Scope.Options property. While the Invoke-WmiMethod cmdlet lets you enable privileges directly through a parameter, this example provides another option:

$system = Get-WmiObject Win32_OperatingSystem
$system.Scope.Options.EnablePrivileges = $true
$system.SetDateTime($class.ConvertFromDateTime("01/01/2007"))

Advanced class features

To retrieve the WMI properties and qualifiers of a class, access the Properties property:

$class = [WmiClass] "Win32_Service"
$class.Properties

Advanced query feature

To configure connection options on a query, such as Packet Privacy and Authentication, set the options on the Scope property:

$credential = Get-Credential
$query = [WmiSearcher] "SELECT * FROM IISWebServerSetting"
$query.Scope.Path = "\\REMOTE_COMPUTER\Root\MicrosoftIISV2"
$query.Scope.Options.Username = $credential.Username
$query.Scope.Options.Password = $credential.GetNetworkCredential().Password
$query.Scope.Options.Authentication = "PacketPrivacy"
$query.get() | Select-Object AnonymousUserName

Discussion

The [Wmi], [WmiClass], and [WmiSearcher] type shortcuts return instances of .NET System.Management.ManagementObject, System.Management.ManagementClass, and System.Management.ManagementObjectSearcher classes, respectively.

As might be expected, the .NET Framework provides comprehensive support for WMI queries, with PowerShell providing an easier-to-use interface to that support. If you need to step outside the support offered directly by PowerShell, these classes in the .NET Framework provide an advanced outlet.

For more information about working with classes from the .NET Framework, see the section called “Work with .NET Objects”.

Improve the Performance of Large-Scale WMI Operations

Problem

You want to perform a large-scale WMI operation across many computers, and want to control how many computers should be managed at a time.

Solution

Use the -ThrottleLimit parameter on the cmdlet, and invoke that cmdlet as a job:

$computers = Get-Content computers.txt
Get-WmiObject Win32_OperatingSystem -Computer $computers -ThrottleLimit 10 -AsJob

1 comment

  1. Richard Siddaway Posted 10 days and 21 hours ago

    The -AsJob parameter should be explained as well as how to retrieve the data from the job

Add a comment

Discussion

One problem with large-scale WMI operations against many computers is that most scripts invoke them sequentially. If your script acts against 10,000 servers, it will usually process the first computer, and then retrieve the results. Then it will process the second computer, and then retrieve its results. Since WMI operations are traditionally network-bound, your script spends the vast majority of its time simply waiting for results from remote computers.

Note

A genesis for this feature was a sobering story we heard from one of our large customers. Their scripts had to deal with so many computers that they would have to start a second script before the first had finished!

The solution to this quandary comes from invoking the commands in parallel. Not entirely in parallel, however, as most machines would buckle under the load of 10,000 active WMI queries. While it is possible to recognize the solution and pitfalls, actually implementing it is something different altogether. Even with the proper skill set, a job manager that supports automatic throttling is usually not high on an administrator's list of priorities when compared to the collection of fires they need to put out.

1 comment

  1. AndrewTearle Posted 15 days and 21 hours ago

    The solution to this quandry < quandary

Add a comment

Instead, PowerShell's WMI cmdlets handle all of this complexity for you. For more information about PowerShell's job support, see the section called “Invoke a Long-Running or Background Command”.

1 comment

  1. AndrewTearle Posted 15 days and 21 hours ago

    Instread < Instead

Add a comment

Convert a VBScript WMI Script to PowerShell

Problem

You want to perform a WMI task in PowerShell, but can find only VBScript examples that demonstrate the solution to the problem.

Solution

To accomplish the task of a script that retrieves data from a computer, use the Get-WmiObject cmdlet:

foreach($printer in Get-WmiObject -Computer COMPUTER Win32_Printer)
{
    $printer.Name
}

To accomplish the task of a script that calls methods on an instance, use the [Wmi] or [WmiSearcher] accelerators to retrieve the instances, and then call methods on the instances like you would call any other PowerShell method.

$service = [Wmi] 'Win32_Service.Name="winmgmt"'
$service | Invoke-WmiMethod -Name ChangeStartMode -ArgumentList "Manual"
$service | Invoke-WmiMethod -Name ChangeStartMode -ArgumentList "Automatic"

1 comment

  1. Richard Siddaway Posted 10 days and 21 hours ago

    Shouldn't the parameter names be included for Invoke-WmiMethod. A reader may not be aware of positional parameters

Add a comment

To accomplish the task of a script that calls methods on a class, use the Invoke-WmiMethod cmdlet, or use the [WmiClass] accelerator to retrieve the class, and then call methods on the class like you would call any other PowerShell method:

Invoke-WmiMethod Win32_Process Create notepad

$class = [WmiClass] "Win32_Process"
$class.Create("Notepad")

Discussion

For many years, VBScript has been the preferred language that administrators use to access WMI data. Because of that, the vast majority of scripts available in books and on the Internet come written in VBScript.

These scripts usually take one of three forms: retrieving data and accessing properties, calling methods of an instance, and calling methods of a class.

Note

Although most WMI scripts on the Internet accomplish unique tasks, PowerShell supports many of the traditional WMI tasks natively. If you want to translate a WMI example to PowerShell, first check that there aren't any PowerShell cmdlets that might accomplish the task directly.

Retrieving data

One of the most common uses of WMI is for data collection and system inventory tasks. A typical VBScript that retrieves data looks like Example 28.3, “Retrieving printer information from WMI using VBScript”.

Example 28.3. Retrieving printer information from WMI using VBScript

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colInstalledPrinters = objWMIService.ExecQuery _
    ("Select * from Win32_Printer")

For Each objPrinter in colInstalledPrinters
    Wscript.Echo "Name: " & objPrinter.Name
    Wscript.Echo "Location: " & objPrinter.Location
    Wscript.Echo "Default: " & objPrinter.Default
Next

The first three lines prepare a WMI connection to a given computer and namespace. The next two lines of code prepare a WMI query that requests all instances of a class. The For Each block loops over all the instances, and the objPrinter.Property statements interact with properties on those instances.

In PowerShell, the Get-WmiObject cmdlet takes care of most of that, by retrieving all instances of a class from the computer and namespace that you specify. The first five lines of code then become:

$installedPrinters = Get-WmiObject Win32_Printer -ComputerName computer

1 comment

  1. Richard Siddaway Posted 10 days and 21 hours ago

    Add computername ??

Add a comment

If you need to specify a different computer, namespace, or query restriction, the Get-WmiObject cmdlets supports those through optional parameters. If you need to specify advanced connection options (such as authentication levels), simply specify those in the -Impersonation and -Authentication parameters to the cmdlet.

In PowerShell, the For Each block becomes:

foreach($printer in $installedPrinters)
{
    $printer.Name
    $printer.Location
    $printer.Default
}

Notice that we spend the bulk of the PowerShell conversion of this script showing how to access properties. If you don't actually need to work with the properties (and only want to display them for reporting purposes), PowerShell's formatting commands simplify that even further:

Get-WmiObject Win32_Printer -ComputerName computer | Format-List Name,Location,Default

1 comment

  1. Richard Siddaway Posted 10 days and 21 hours ago

    Add computername to match VBscript version?

Add a comment

For more information about working with the Get-WmiObject cmdlet, see the section called “Access Windows Management Instrumentation Data”.

Calling methods on an instance

Although data retrieval scripts form the bulk of WMI management examples, another common task is to call methods of an instance that invoke actions.

For example, Example 28.4, “Changing the startup type of a service from WMI using VBScript” changes the startup type of a service.

Example 28.4. Changing the startup type of a service from WMI using VBScript

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
    ("Select * from Win32_Service where StartMode = 'Manual'")

For Each objService in colServiceList
    errReturnCode = objService.ChangeStartMode("Disabled")
Next

The first three lines prepare a WMI connection to a given computer and namespace. The next two lines of code prepare a WMI query that requests all instances of a class and adds an additional filter (StartMode = 'Manual') to the query. The For Each block loops over all the instances, and the objService.Change(…) statement calls the Change() method on the service.

In PowerShell, the Get-WmiObject cmdlet takes care of most of the setup, by retrieving all instances of a class from the computer and namespace that you specify. The first five lines of code then become:

$services = Get-WmiObject Win32_Service -Filter "StartMode = 'Manual'"

If you need to specify a different computer or namespace, the Get-WmiObject cmdlets supports those through optional parameters. If you need to specify advanced connection options (such as authentication levels), simply specify those in the -Impersonation and -Authentication parameters to the cmdlet.

In PowerShell, the For Each block becomes:

foreach($service in $services)
{
    $service.ChangeStartMode("Disabled")
}

For more information about working with the Get-WmiObject cmdlet, see the section called “Access Windows Management Instrumentation Data”.

Calling methods on a class

Although less common than calling methods on an instance, it is sometimes helpful to call methods on a WMI class. PowerShell makes this work almost exactly like calling methods on an instance.

For example, a script that creates a process on a remote computer looks like this:

strComputer = "COMPUTER"
Set objWMIService = GetObject _
    ("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")

objWMIService.Create("notepad.exe")

The first three lines prepare a WMI connection to a given computer and namespace. The final line calls the Create() method on the class.

In PowerShell, the Invoke-WmiMethod cmdlet lets you easily work with methods on a class. The entire segment of code then becomes:

Invoke-WmiMethod "\\COMPUTER\Root\Cimv2:Win32_Process" Create notepad.exe

For more information about invoking methods on WMI classes, see the section called “Invoke a Method on a WMI Class”.

You must sign in or register before commenting
*
*
*
*
*

Atom Icon Comments on this page or Comments on the whole book.