CIM – Taking the leap

If you use PowerShell regularly, chances are that you have used WMI. Microsoft introduced a new set of cmdlets in PowerShell version 3, the CIM cmdlets, which is meant as the new and improved way of interacting with WMI/CIM.

But I know from personal experience that it takes times to learn something new, and when the old way works, why bother right?

After reading this blog post from Richard Siddaway, I took the leap and converted one of my old functions that uses WMI, to use the new CIM cmdlets, and in the process I created a template for creating functions that uses CIM to query computer(s) for information. I’m sharing it here in hope that others might take the leap as well, and hopefuly you will find this template useful.

The function in the template will try to connect to a computer using WSMAN first, but fall back to DCOM if that fails. This way you can still use it against legacy systems as well.


function Get-Something {
<#
.SYNOPSIS
Short description of function.
.DESCRIPTION
Longer description of function.
.EXAMPLE
Get-Something -ComputerName 'Computer01'
Example description
.EXAMPLE
$servers | Get-Something
Example description
.INPUTS
System.String
System.Management.Automation.Credential
.NOTES
General notes about the function
Author: Øyvind Kallstad
This function uses CIM to query one or more computers.
A CIM session is saved in the current PowerShell session with the name of the remote computer, and will be re-used if possible.
This means that if you run this function against a computer and you already have a session, you don't have to use the Credential
parameter after the first time. The function will try to use 'Wsman' as protocol, but will fall back to using 'Dcom' if needed.
NOTE! This is just a template!
.LINK
Related link
#>
[CmdletBinding()]
[OutputType([PSObject])]
param (
# Specifies the target computer. Enter a fully qualified domain name, NetBIOS name, or an IP address. When the remote computer is in a different domain than the local computer,
# the fully qualified domain name is required.
[Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[ValidateNotNullorEmpty()]
[string[]] $ComputerName = $env:COMPUTERNAME,
# Specifies a user account that has permission to perform this action.
[Parameter()]
[System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty,
# Use this parameter to force the creation of a new CIM session. The default behaviour is to save the session and reuse it if possible.
[Parameter()]
[switch] $ForceNewCimSession
)
begin {
# code to execute before pipline processing
}
process {
foreach ($computer in $ComputerName) {
try {
# define hashtable for Test-WSMan properties
$wsmanProperties = @{
ComputerName = $computer
ErrorAction = 'SilentlyContinue'
}
if ($PSBoundParameters['Credential']){
#$wsmanProperties.Authentication = 'Basic'
# if you can't use Kerberos authentication, comment out this line and uncomment the line above to use Basic authentication instead
$wsmanProperties.Authentication = 'Kerberos'
$wsmanProperties.Credential = $Credential
}
# check if wsman is responding
$wsmanTest = Test-WSMan @wsmanProperties
# based on the result of the wsman test, we decide on the protocol to use for the cim session
if (-not([string]::IsNullOrEmpty($wsmanTest))) {
$cimSessionOption = New-CimSessionOption -Protocol Wsman
Write-Verbose 'Using protocol "Wsman"'
}
else {
$cimSessionOption = New-CimSessionOption -Protocol Dcom
Write-Verbose 'Using protocol "Dcom"'
}
# define hashtable for cim session properties
$cimSessionProperties = @{
Name = $computer
ComputerName = $computer
SessionOption = $cimSessionOption
Verbose = $false
ErrorAction = 'Stop'
}
if ($PSBoundParameters['Credential']){ $cimSessionProperties.Credential = $Credential}
# first check to see if a cim session already exist, if so use this – if not, we create a new one
# if -ForceNewCimSession is used, always create a new cim session
if ((-not($cimSession = Get-CimSession -Name $computer -ErrorAction SilentlyContinue)) -or ($ForceNewCimSession)) {
Write-Verbose 'Creating new CIM session'
$cimSession = New-CimSession @cimSessionProperties -SkipTestConnection
} else { Write-Verbose 'Using existing CIM session' }
#####
## YOUR CODE GOES HERE – example:
Write-Output (Get-CimInstance -CimSession $cimSession -Query 'SELECT * FROM Win32_OperatingSystem' -Verbose:$false -ErrorAction Stop)
#####
}
catch {
# if the connection fail we don't want to keep the session
Remove-CimSession -Name $computer -ErrorAction SilentlyContinue
Write-Warning "At line:$($_.InvocationInfo.ScriptLineNumber) char:$($_.InvocationInfo.OffsetInLine) Command:$($_.InvocationInfo.InvocationName), Exception: '$($_.Exception.Message.Trim())'"
}
}
}
end {
# code to execute after pipline processing
}
}

Leave a comment