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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |