August 19th, 2013

CIM Cmdlets – Some Tips & Tricks

PowerShell Team
PowerShell Team

Common Information Model (CIM) cmdlets have been around for a while, and come in handy when you are performing any CIM operation in PowerShell. They are easy to use, and provide a good user experience. In this blog post, I cover a few tips and tricks that can be useful for users of CIM cmdlets.

To get started, let’s get the complete list of cmdlets. The PowerShell module name for these cmdlets is CimCmdlets, and we can use the Get-Command cmdlet to see the cmdlets exposed by this module.

 

PS :> # Get all CIM Cmdlets

PS :> Get-Command –module CimCmdlets

CommandType         Name                                           ModuleName

——————–     ————————————-        ———————-                                                 

Cmdlet                   Get-CimAssociatedInstance           CimCmdlets

Cmdlet                   Get-CimClass                                    CimCmdlets

Cmdlet                   Get-CimInstance                              CimCmdlets

Cmdlet                   Get-CimSession                                CimCmdlets

Cmdlet                   Invoke-CimMethod                         CimCmdlets

Cmdlet                   New-CimInstance                            CimCmdlets

Cmdlet                   New-CimSession                              CimCmdlets

Cmdlet                   New-CimSessionOption                  CimCmdlets

Cmdlet                   Register-CimIndicationEvent         CimCmdlets

Cmdlet                   Remove-CimInstance                      CimCmdlets

Cmdlet                   Remove-CimSession                        CimCmdlets

Cmdlet                   Set-CimInstance                                CimCmdlets

  

Tip#1: Working with CIM sessions

A CIM session is a client-side object representing a connection to a local or remote computer. The CIM session contains information about the connection, such as ComputerName, the protocol used for the connection, session ID, and instance ID.

a.       When you are trying to connect to a remote machine, you might have to pass credentials. The New-CimSession cmdlet consumes a PSCredential object when credentials are used to create a CIM session. The constructor of PSCredential object accepts only a secure password string.

 

PS:> # Type in the password when you are prompted

PS:> .$creds = Get-Credential -Credential username

 

PS:> # Save credentials for future use

PS:> $creds | Export-Clixml -Path c:\a.clixml

 

PS:> # Use the saved credentials when needed

PS:> $savedCreds = Import-Clixml -Path C:\a.clixml

 

PS:> # Create CimSession with Credentials

PS:> $session = New-CimSession –ComputerName “machineName”  -Credential $savedCreds

 

b.      If the ComputerName parameter is added, the protocol used is WS-Management (WS-Man).

 

PS:> # If the ComputerName parameter is not added, the cmdlet uses DCOM/COM

PS:> # Creates DCOM session

PS:> $session = New-CimSession

PS:>  # Performs enumerate over DCOM

PS:> $inst = Get-CimInstance Win32_OperatingSystem                 

 

PS:> # If ComputerName is added, the cmdlets go over WS-Man

PS:>  $session = New-CimSession –ComputerName localhost

PS :> $inst = Get-CimInstance Win32_OperatingSystem –ComputerName localhost

 

c.       If you use any parameter except “–Protocol DCOM” with New-CimSessionOption, the session option helps generate the WS-Man session.

PS:> # DCOM Session

PS:> $sessionOp = New-CimSessionOption –Protocol DCOM

PS:> $sessionDcom = New-CimSession –SessionOption $sessionOp –ComputerName localhost

 

PS:> # WS-Man Session: the parameter UseSSL added to the New-CimSessionOption command specified the WS-Man protocol

PS:> $sessionOp2 = New-CimSessionOption –UseSSL

PS:> $sessionWSMAN = New-CimSession –SessionOption $sessionOp2 –ComputerName localhost

 

d.      The Default protocol in your New-CimSessionOption command corresponds to WS-Man.

 

PS:> # Create a CimSession using Default protocol

PS:> New-CimSession –ComputerName localhost –SessionOption (New-CimSessionOption –Protocol Default) 

 

 e.      If you are performing a large number of remote operations,, I recommend that you reuse sessions. This can provide a significant performance gain.

PS:> # Perform Get-CimInstance using computerName

PS:>$time 1 = Measure-Command { 1..100 | %{ Get-CimInstance –ClassName CIM_ComputerSystem –ComputerName remoteMachine } }

 

PS:> # Create a CimSession

PS:> $session = New-CimSession –ComputerName remoteComputer

PS:> $time2 = Measure-Command { 1..100 | %{ Get-CimInstance –ClassName CIM_ComputerSystem –CimSession $session } }

 

In the above example, $time1 > $time2, because the Get-CimInstance cmdlet calls that use ComputerName parameter create a CIM session under the hood every time. In the second scenario, where we use an explicitly created CIM session, the cost of creating a CIM session in each call is not there.

  

Tip#2: Fan-out

 a.       Working with multiple servers

All CIM cmdlets accept an array of CIM sessions or computer names. These can be used to perform operations on multiple servers in one line.

 

PS :> # Create multiple sessions

PS :> $allSessions = New-CimSession -ComputerName “machine1”, “machine2”, “machine3” –Credential $credentials

 

PS :> # Fan-out with CIM session Array

PS :> Get-CimInstance –ClassName Win32_OperatingSystem –CimSession $allSessions

 

PS :> # Reboot all machines in one line

PS :> Invoke-CimMethod –ClassName Win32_OperatingSystem –MethodName Reboot –CimSession $allSessions

 

PS:> # OR

 

PS:> Invoke-CimMethod –ClassName Win32_OperatingSystem –MethodName Reboot –ComputerName “Machine1”, Machine2”,”Machine3”

 

b.      Don’t have to pass session if you use pipes. Instances are machine-aware

If an instance received from one cmdlet is piped to another cmdlet, the cmdlet on the right side of the pipe is not required to specify computer names or CIM sessions, because the instances are machine-aware. The cmdlet on the right-side of the pipe can extract machine-related information from the instances.

 

PS:> # Get instance from a class

PS:> $session = New-CimInstance -ComputerName machine1

PS:> $inst = Get-CimInstance –Query “Select * from TestClass where v_key = 2” –Namespace root/test –CimSession $session

 

PS:> # Pass CIM instance

PS:> $props = @{ boolVal = $true }

PS:> $inst | Set-CimInstance –CimInstance $inst –Property $props

 

# OR

 

PS:> # Pipe result of get into set

PS:> Get-CimInstance –Query “Select * from TestClass where v_key = 2” –Namespace root/test –CimSession $session | Set-CimInstance –CimInstance $inst –Property $props

 

  

Tip#3: Working with non-Windows CIMOMs

a.       Connecting to devices that need resource URIs

Some vendors support non-DMTF resource URIs, (here DMTF stands for Distributed Management Task Force) but the parameter set of CIM cmdlets that uses ClassName might not work in that scenario. CIM cmdlets offer a parameter set that accepts non-DMTF resource URIs, and lets you manage those devices. The following example demonstrates this:

PS:> # Non DMTF resource URI

PS:> $resourceuri = “http://intel.com/wbem/wscim/1/amt-schema/1/AMT_PETFilterSetting”

 

PS :> # Get instances

PS:> $inst = Get-CimInstance -Namespace $namespace -ResourceUri $resourceuri -CimSession $session

 

PS :> # Query instances

PS:> $inst = Get-CimInstance -Query $query -Namespace $namespace -ResourceUri $resourceuri -CimSession $session

 

PS:> # Modify instance

PS:> $propsToModify = @{LogOnEvent=$false}

PS:> Set-CimInstance -InputObject $inst -Property $ propsToModify -ResourceUri $resourceuri -CimSession $session

 

b.      If the Common Information Model Object Manager (CIMOM) does not support TestConnection, the New-CimSession command will fail. How to make sure a session can be created with such a CIMOM?

 

PS:> # Creating CIM session when the server/CIMOM does not support TestConnection

PS:> $session = New-CimSession –CN “machineName”  -Credential $creds –SkipTestConnection

 

c.       If the CIMOM is listening on a port other than the default port, you can make sure New-CimSession calls the particular port.

 

PS:> # Default HTTP port for WS-Man on Windows

PS:> $httpPort = 5985                       

PS:> # Default HTTPS port for WS-Man on Windows

PS:< $httpsPort = 5986       

 

PS:> # Port parameter is exposed by New-CimSession and not New-CimSessionOption

PS:> $session = New-CimSession –CN “machineName”  -Credential $creds –Port $httpPort

PS:> # If using HTTPS.

PS:> $sop = New-CimSessionOption –UseSSL

PS:> $session = New-CimSession –CN “machineName”  -Credential $creds –Port $httpsPort

 

  

Tip#4: Get associated instances

Associations are important in the CIM world, as they define the relationship between two classes. Get-CimAssociatedInstance provides a way of figuring out these relationships.

 

PS :> # Get instance of Win32_LogicalDisk class with DriveType =3 (hard drives)

PS :> $disks = Get-CimInstance -class Win32_LogicalDisk -Filter ‘DriveType = 3’

 

PS :> # Get the all instances associated with this disk

PS :> Get-CimAssociatedInstance -CimInstance $disks[0]

 

PS :> # Get instances of a specific type

PS :> Get-CimAssociatedInstance -CimInstance $disks[0] -ResultClassName Win32_DiskPartition

 

PS :> # Finding associated instances through a specific CIM relationship

PS :> Get-CimAssociatedInstance -CimInstance $disks[0] -Association Win32_LogicalDiskRootDirectory

 

 

Tip#5: Passing ref and embedded instances

Did you know? If you pass an instance as REF, only key values get passed on to the provider by the infrastructure; for example, even if all the properties are populated inside the instance, the provider only gets to see the key values.

There are some edge-case scenarios that come up with REF arrays.

a.       If the instances are created with the ClientOnly parameter in a New-CimInstance command, while passing it into a method that expects a REF array, we should typecast it as ref[].

PS:> # Create an instance with New-CimInstance -ClientOnly : Type cast it to [ref[]]

PS:> $inst1 = New-CimInstance –className foo –Namespace root/test –Property @{A= 1; B= 2} –ClientOnly

 

PS:> $inst2 = New-CimInstance –ClassName foo –Namespace root/test –Property @{A= 3; B= 4} –ClientOnly

PS:> $instArray = @($inst1, $inst2)

PS:> Invoke-CimMethod –ClassName Class1 –Namespace root/test –Method MethodRefArray –Property @{vals = [ref[]] $instArray}

 

b.      If the instances come from Get-CimInstance, and are the same as a server object, then method invocation should be done by typecasting that instance array as Ciminstance[].

 

PS :> # Get an instance from Get-CimInstance : Typecast it to [Ciminstance[]]

PS :> $inst = Get-CimInstance –ClassName foo –Namespace root/test

PS :> Invoke-CimMethod –ClassName Class1 –Namespace root/test –Method MethodRefArray –Property @{vals = [Ciminstance[]] $inst}

 

c.       The next example shows invoking methods with embedded instances.

PS :> $nums = New-CimInstance –ClassName numbers -Namespace root/test -Property @{numbers = @([int64]5 , [int64]6); count = [uint32]2} –Local

 

PS :> Invoke-CimMethod  -ClassName TestCalculator -MethodName AddNumbers  -Arguments @{numbers = $nums} –Namespace root/test

 

PS :> $nums2 = Get-CimInstance –ClassName numbers -Namespace root/test

PS :> Invoke-CimMethod -ClassName TestCalculator -MethodName AddNumbers  -Arguments @{numbers = [CimInstance] $nums} -NS root/test

 

  

Tip#6: Using indications

Receiving indications allows the developer to notify the consuming application that certain system configuration data has changed, without the application having to poll Windows Management Instrumentation (WMI) continuously for this data. From the CIM cmdlet layer, registering for indications is easy. The following script block describes how to register, get, and unsubscribe from indications.

PS :> # Register for an event/indications

PS :> Register-CimIndicationEvent -ClassName Test_IndicationClass -Namespace root\test

 

PS :> # Get all events generated so far

PS :> $x = Get-Event

 

PS :> # Unregister a particular event.

PS :> $sourceID = $x[0].SourceIdentifier

PS :> Unregister-Event -SourceIdentifier $sourceID

 

PS :> # Clean up all the events received so far

PS :> Remove-Event *

 

# OR

 

PS :> # Define your own SID

PS:> $sid = “TestSID”

PS:> Register-CimIndicationEvent -ClassName Test_IndicationClass -Namespace root\test –SourceIdentifier $sid

 

PS:> $x = Get-Event –SourceIdentifier $sid

PS:> Unregister-Event -SourceIdentifier $sid

 

Tip#7: Typecasting/Using DateTime/Using UInt8

While using a hash table as input to the parameters of CIM cmdlets, you might have to typecast data that is being passed. The simple rules here are:

·         If the class schema is passed while running the cmdlet, the data type is discovered at run time, so you don’t have to explicitly cast the values.

·         If the class schema is not passed, the default data types are used, which can cause failures while running the cmdlets. Typecasting is needed in this scenario.

The following sample code clarifies this:

PS:> Invoke-CimMethod -ClassName TestCalculator -Namespace root/test -MethodName Add –Arguments @{Left = 4; right=5}

 

Invoke-CimMethod : Type mismatch for parameter “Left“   => If Left and Right are SInt64 values

 

PS:> # The above failure happened because by default all values are treated as UInt32.

 

PS:> Invoke-CimMethod -ClassName TestCalculator -Namespace root/test -MethodName Add –Arguments @{Left = [int64]4; right=[int64]5}

 

PS:> # If the CimClass parameter is used, no typecasting is needed.

PS:> $c = Get-CimClass -Namespace root/test -ClassName TestCalculator

PS:> Invoke-CimMethod -CimClass $c -MethodName Add -Arguments @{Left = 4; right=5}

 

While using any DateTime type parameter, we must typecast the string representation of DateTime. Similarly, while passing in a value that is UInt8, we must typecast it to Byte.

PS:> $inst = New-CimInstance -ClassName TestClass -Namespace root\test -Key v_uint8 -Property @{ v_uint8 = [byte] 3; v_dateTime = [DateTime] “12/31/1899 3:59:59 PM” }

  

Tip#8 Passing operationOptions

There is no way of passing operation Options values to the WMI provider from CIM cmdlets. To pass operationOptions values to your provider, you might have to take the following route:

PS :> $s = New-CimSession

 

PS :> # Create MethodParameterCollection

PS :> $x = New-Object Microsoft.Management.Infrastructure.CimMethodParametersCollection

PS :> $param = [Microsoft.Management.Infrastructure.CimMethodParameter]::Create(“number”,  40, [Microsoft.Management.Infrastructure.cimtype]::UInt64, [Microsoft.Management.Infrastructure.CimFlags]::None)

PS :> $x.Add($param)

 

PS :> Create a OperationOption object

Ps :> $operationOption = new-object                         Microsoft.Management.Infrastructure.Options.CimOperationOptions

 

PS :> $operationOption.SetCustomOption(“TEST_SET_NAMESPACE”, $true, $false)

 

PS :> # Invoke the method

PS :> $s.InvokeMethod(“root/test”, “TestalCalculator”, “PrimeFactors”, $x, $operationOption)

PS :> $returnVal.OutParameters[“factors”].Value.CimSystemProperties        

  

Tip#9 Instances of an AssociationClass only have references to the two ends of the association, and not actual instances

When instances of an association class are enumerated, the properties returned contain the references to the two end points of that association. As these properties are reference-only, only key values are populated.

 

PS :> Get-CimInstance win32_DiskDriveToDiskPartition

Antecedent :   Win32_DiskDrive (DeviceID = \\.\PHYSICALDRIVE0)                    

Dependent :    Win32_DiskPartition (DeviceID = “Disk #0, Partition #0”)            

 

  

Tip#10 Making Get/Enumerate efficient

a.       Save a round trip by using -ClientOnly to create instances

If the key values of an instance are known, and the intended operation is to get an instance from the server, then the user can create a ClientOnly instance of a class, and then run Get-CimInstance on it. This saves one round trip to the server.

PS:> $instLocal = New-CimInstance –className foo –Namespace root/test –Property @{A= 1; B= 2} –ClientOnly

 

PS:> $instFromServer = Get-CimInstance –InputObject $instLocal –CimSession $session

 

b.      Only get the key properties.

If the whole instance is not needed, and the intent is only to check the key properties of an instance, the user can get key properties of an instance only, if desired.

 

PS:> $inst = Get-CimInstance -Class Win32_Process –KeyOnly

 

PS:> # This can be used to invoke a method

PS:> Invoke-CimMethod -InputObject $inst -MethodName “Terminate”

 

 

c.       How to refresh instance data in PowerShell without grabbing the WMI object again.

The original object remains untouched, but the data refreshes.

PS:> # Get instance of a class

PS:> $p = Get-CimInstance -ClassName Win32_PerfFormattedData_PerfOS_Processor

PS:> # Perform get again by passing the instance received earlier, and get the updated properties. The value of $p remains unchanged.

PS:> $p | Get-CimInstance | select PercentProcessorTime

 

I hope these tips and tricks will make your experience with CIM cmdlets even better. If you have any questions regarding these cmdlets, please feel free to let us know.

 

Thanks

Vaibhav Chugh [MSFT]

Standards Based Management

Category
PowerShell

Author

PowerShell Team
PowerShell Team

PowerShell is a task-based command-line shell and scripting language built on .NET. PowerShell helps system administrators and power-users rapidly automate tasks that manage operating systems (Linux, macOS, and Windows) and processes.

0 comments

Discussion are closed.