Monday, March 24, 2014

PowerShell Cim Cmdlet to PowerShell 2.0 or older

Starting in PowerShell 3.0, Microsoft introduces a new set of cmdlets to manage servers or devices that complies to DMTF standards. These new set of cmdlets, CIM (Common Information Model (CIM) Cmdlets allow IT professional to better manage their data center especially when it consists of servers from different vendors.

Before PowerShell 3.0, IT professional commonly use WMI Cmdlets (WMI is Windows standard of the CIM Server) to obtain resources information for Windows, and WSMan Cmdlets for Non-Windows. In order to allow and simplify management on heterogeneous environment, a standard compliance and richer PowerShell CIM Cmdlets are introduced. You can find a list of CIM Cmdlets from this TechNet article. This msdn article provide a good introduction of CIM cmdlet as well comparison with the older WMI.

Windows Server 2012 and Windows 8 shipped with PowerShell 3.0 which support these new CIM Cmdlets. For servers or devices with older version of PowerShell, it doesn't support CIM Cmdlets directly.

For example, if we want to get some processor information of a remote server (e.g. Server1), traditionally we use WMI cmdlets like this,

Get-WmiObject -Class Win32_Processor -ComputerName Server1 | Select-Object -Property SocketDesignation, NumberOfCores, NumberOfLogicalProcessors, CurrentClockSpeed

Win32_Processor represents instances for each processor
Get-WmiObject get instance of WMI class in this case Win32_Processor

To use the new CIM Cmdlet, for the remote server (e.g. Server1) that has at least PowerShell 3.0, we could execute the command like this (try using the tab completion for ClassName like *processor for for richer experience),

Get-CimInstance -ClassName CIM_Processor -ComputerName Server1 | Select-Object SocketDesignation, NumberOfCores, NumberOfLogicalProcessors, CurrentClockSpeed

CIM_Processor represents instance for each processor. This CIM_Processor class is parent class for Win32_Processor
Get-CimInstance gets the CIM instances of a class, in this case CIM_Processor

If the same command issued to obtain processor information from another server (e.g server2) that currently installed with PowerShell 2.0,

The command failed.

The reason is because Get-CIMInstance Cmdlet is using WinRM (Windows implementation of WSMAN protocol) which is only supported from PowerShell 3.0. In order to execute the Get-CIMInstance command on Server2 with PowerShell 2.0 version installed, we have to force the CIM cmdlet to use DCOM protocol (used by WMI) which is supported in all PowerShell version (As of this post).

To do that, we use the CIM Session which provide an option of using DCOM or WSMAN. In this case, select the DCOM and execute the Get-CIMInstance against the CIM session.

$so = New-CimSessionOption -Protocol Dcom
$s = New-CimSession -ComputerName Server2 -SessionOption $so
Get-CimInstance -ClassName CIM_Processor -CimSession $s |
Select-Object -Property SocketDesignation, NumberOfCores, NumberOfLogicalProcessors, CurrentClockSpeed

It is important to know which protocol is being used as it uses different ports which will affect firewall exception setup.

If the firewall is not configured correctly, you may receive this error.

New-CimSession : The RPC server is unavailable.

DCOM assigns TCP port dynamically from 1024 through 65535. In order for WMI cmdlets to connect the remote server successfully, at remote server enable the Windows Firewall: Allow remote administrator exception (gpedit.msc > local computer policy > computer configuration > administrative templates > network, network connections > windows firewall > domain/standard profile), which will enable these RPC firewall rules as shown below.

For asynchronous callback from remote computer, the local computer need to enable the Windows Management Instrumentation (Async-In) firewall rule and sometimes (DCOM-In) firewall rule. One example is the remote SQL Server Configuration Manager. More information at this post.

The easier way for WMI firewall setup I found is go to control panel > System and Security > Windows Firewall >  Allow a program or feature through Windows Firewall, Select Windows Management Instrumentation (WMI).

This will enable the firewall rules as shown below.

As long as there are no RPC or other similar firewall rules blocking the ports, these WMI firewall take care of the required WMI firewall exceptions.

WinRM protocol is a SOAP (standard simple object protocol) based protocol that uses TCP port 5985 for HTTP transport and 5986 for HTTPS.

To enable the firewall, you can run winrm quickconfig on powershell on the remote server, which will enable the firewall rules show below.

Similarly, we could configure the Windows Remote Management through Windows Firewall and Allow a program or feature through Windows Firewall.

These are the firewall rules enabled.

The compatibility mode is for the older WinRM (WinRM 1.1) which uses the common port 80. Since WinRM 2.0, the port has changed to 5985. Also, if required, HTTPS firewall rule could be configured.

If the firewall for WinRM is not configured correctly, you may receive this error when using CIM Cmdlets with the default WinRM (or specified in the session option to use WSMAN) protocol.

Get-CimInstance : WinRM cannot complete the operation. Verify that the specified computer name is valid, that the computer is accessible over the network, and that a firewall exception for the WinRM service is enabled and allows access from this computer. By default, the WinRM firewall exception for public profiles limits access to remote computers within the same local subnet.

Hope this post help you to use CIM cmdlets against older PowerShell version and the firewall setup.