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 Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s