Microsoft Windows Management Instrumentation (WMI) remoting is an essential part of Windows PowerShell.  WMI remoting was one of the primary ways of making configuration changes on remote systems.

Prerequisite

1. Firewall equirement 

Windows Server 2012 Permits WMI by default, but the win8 or 10 does not, which means attempts to connect result in a remote procedure call (RPC) error.

The best way to manage the Windows 8/10 client is to use group policy to permit the use of WMI inbound. Keep in mind, the issue here is the Windows  rewall, not WMI itself. The steps to use group policy to con gure WMI appear here:

1). Open the group policy management console.

2). Expand the Computer Config > Policies > Windows Settings > Security Settings > Windows Firewall With Advanced Security > Windows Firewall With Advanced Security > Inbound Rules node.

3). Right-click in the working area and choose New Rule.

4). Choose the Prede ned option, and select Windows Management Instrumentation (WMI) from the drop-down list.

5). There are a number of options here, but you should start with one: the (WMI-In) option with the Domain pro le value. If you aren’t sure what you need, then just remember you can come back and add the others later. Click Next.

6). Allow the connection to  finish.

The error code will be like:

The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)

2. Permission 

Additionally, the remote caller must be a member of the local administrators group on the target machine. By default, members of the Domain Admin group are placed into the local administrators group when the system joins the domain. If you attempt to make a remote WMI connection without membership in the local admin group on the target system, an Access Denied error is raised.

The error code is different from the firewall error code:

Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

We will talk about how to supply credentials for remote connection in next part.

Supplying alternate credentials for the remote connection

There are two common ways of supplying the credential object for the remote connection.

First way is to type the domain and user name values directly into the credential parameter. E.g.

gwmi win32_bios -cn test_pc -Credential test\administrator

Then a dialog box appears prompting for the password to use for the connection. The only problem is that you have to enter the password each time you run the script.

Store the credentials in variables.

To store your credentials for later consumption, use the Get-Credential Windows PowerShell cmdlet to retrieve your credentials and store the resulting credential object in a variable. If you work with multiple systems with different passwords, it makes sense to create variables that will facilitate remembering which credentials go to which system.  Then you can use Get-WMIObject to get the info. The returned WMI object contains the name of the system in the __Server variable, but the default display does not include this information.

e.g, you can retrieve bios info of three computers:

$credential = Get-Credential -Credential test\administrator

$cn = "w8s504","hyperv2","hyperv3"

gwmi win32_bios -cn $cn -Credential $credential | select smbiosbiosversion, manufacturer, name, serialnumber, __server

WMI does not support alternate credentials for a local connection, but Windows PowerShell remoting does. Using Windows PowerShell remoting, you can con gure different access rights for the remote endpoint that do not require admin rights on the remote system.

Windows PowerShell remoting also permits running WMI commands with alternate credentials from within the same Windows PowerShell session against the local computer.

You can use Enable-PSRemoting cmdlet to configure the firewall and services on the target machine first with local admin privilege.

Over all, the disadvantages of using WMI removing include:

■  WMI remoting requires special  rewall rules to permit access to client systems.

■  WMI remoting requires opening multiple holes in the  rewall.

■  WMI remoting requires local administrator rights.

■  WMI remoting provides no support for alternate credentials on a local connection.

■  WMI remoting output does not return the name of the target system by default.

 

Use common Information Model (CIM) classes to query WMI classes

Before diving into the CIM, let’s have a review about the difference between WMI and CIM.

First, you have to remember that CIM = WMI = CIM. CIM is an open standard from the Distributed Management Task Force (DMTF), with the latest version introduced in January 2016. CIM provides a common definition of management information for systems, networks, applications, and services, and it allows for vendor extensions. WMI is the Microsoft implementation of CIM for the Windows platform. For more, read here.

There are several ways of using the Common Information Model (CIM) classes to perform remote WMI queries .The most basic way is to use the Get-CimInstance cmdlet, which requires several steps:

1.  Use the New-CimSession cmdlet to create a new CIM session, and Store the returned session in a variable. You can keep the connection open and send multiple commands to the same machines in this way.

2. Use Get-CIMInstance cmdlet. Supply the stored CIM session from the variable to the -cimsession parameter.

E.g, we want to get the bios info of a remote computer:

$creden=Get-credential mcc\frank
$test=New-CimSession -ComputerName "test-vm" -Credential $creden
Get-CimInstance -CimSession $test -ClassName win32_bios

And the result will be:

SMBIOSBIOSVersion : VirtualBox
Manufacturer : innotek GmbH
Name : Default System BIOS
SerialNumber : 0
Version : VBOX - 1
PSComputerName : test-vm
Work on dates

Compared to WMI, Get-CimInstance automatically converts the date from a UTC string to a datetime type.

Get-WmiObject  has a few awkward edges. A particular pain point is working with dates, for example:

Get-WmiObject -Class Win32_OperatingSystem | select LastBootUpTime
LastBootUpTime
————–
20160131094454.487954+000

The objects produced by Get-WmiObject have a couple of methods (convertToDateTime )added by the PowerShell team to make life easier:

Get-WmiObject -Class Win32_OperatingSystem | select @{N=’LastBootTime’; E={$_.ConvertToDateTime($_.LastBootUpTime)}}
LastBootTime
————
31/01/2016 09:44:54

However, the cim give us a readable result straightway:

$bios=Get-CimInstance -CimSession $test -ClassName win32_bios
$bios.ReleaseDate
Friday, 1 December 2006 11:00:00 AM

We can verify the data type:

$bios.ReleaseDate.gettype()
IsPublic IsSerial Name
-------- -------- ----
True     True     DateTime
BaseType
--------
System.ValueType
Work on remote results

When working with remote systems, it may be important to consider the network bandwidth and the cost of repeatedly retrieving unfiltered data.

There are basically two choices—the first choice involves gathering the information and storing it in a local variable. Then just use the needed part of the data.

Important In potentially bandwidth-constrained situations, it is a best practice to store data retrieved locally to facilitate reuse of the information at a later time. The easiest place to store the data is in a variable, but do not forget about storing the data in XML for a more persisted storage. Using the Export-CliXML cmdlet is extremely easy and preserves the data relationships well.

e.g.

$process = Get-CimInstance -CimSession $session -ClassName win32_process

$process | ft name, processID -AutoSize

However, this approach is not ideal if the data changes from time to time.

The second approach involves  ltering the data at the source and only returning the needed information to the local client machine. There are two ways of doing this: the first is to use the Windows PowerShell -property and – filter parameters to reduce the data returned; the second is to use a native WQL query to reduce the data.

The  first parameter, the -property parameter, reduces properties returned, but it does not reduce instances. The second parameter, the – filter parameter, reduces the instances returned, but does not reduce the number of properties.

Eg.

We want to get the services, and only show the Name and startmode(auto, manual):

New-CimSession -ComputerName w8s504 -Credential $creden
Get-CimInstance -ClassName win32_service -CimSession $session -Property name, startmode

If we just want to show the services that are running while showing the name and startmode:

Get-CimInstance -ClassName win32_service -CimSession $session -Property name, startmode -Filter "state = 'running'" | sort startmode | ft name, startmode -AutoSize
Running WMI jobs

You can run the remote WMI job according to the circumstances:

1.  If DCOM is not an issue and you are using the Get-WMIObject cmdlet to work with remote systems, you can use Get-WMIObject cmdlet and specify the -asjob parameter.

The -asjob switched parameter is used to ensure that the command runs as a job.

Once you do this, use the Get-Job cmdlet to check on the status of the job, and use Receive-Job to receive the job results.

e.g.

gwmi win32_bios -ComputerName dc -AsJob

Id     Name PSJobTypeName   State   HasMoreData   Location

--     ---- -------------   -----   -----------   --------

    Job2 WmiJob          Running True          dc

To check the job status:

Get-Job -id 2 

Id     Name  PSJobTypeName   State              HasMoreData       Location

--     ----  -------------   -----              -----------       --------

2      Job2  WmiJob          Completed          True              dc

Note that the PSJobTypeName is WmiJob.

 

2. If you don’t have DCOM and RPC access to the remote system, you can use the Invoke-command cmdlet to run the WMI command on the remote system as a job. You also need the -asjob parameter on the Invoke-command cmdlet.

e.g.

Invoke-command -ComputerName test-vm -credential $creden -ScriptBlock {gwmi win32_service} -AsJob

Id     Name PSJobTypeName   State   HasMoreData   Location

--     ---- -------------   -----   -----------   --------

    Job4 RemoteJob       Running True          test-vm

Notice this time the PSJobTypeName is RemoteJob, not wmijob.

You can also use the CIM cmdlets as jobs by using the Invoke-command.

WMI VS CIM

Should I use CIM or WMI with Windows PowerShell?

First, you have to remember that CIM = WMI = CIM. CIM is an open standard from the Distributed Management Task Force (DMTF), with the latest version introduced in January 2016. CIM provides a common definition of management information for systems, networks, applications, and services, and it allows for vendor extensions. WMI is the Microsoft implementation of CIM for the Windows platform.

Get-WmiObject is one of the original PowerShell cmdlets.  It was enhanced in PowerShell 2.0 when the other WMI cmdlets were introduced. In PowerShell 1.0, Get-WmiObject was the only cmdlet with the option to access another system.

The big drawback to the WMI cmdlets is that they use DCOM to access remote machines. DCOM isn’t firewall friendly, can be blocked by networking equipment, and gives some arcane errors when things go wrong.The CIM cmdlets appeared in PowerShell 3.0 as part of the new API for working with CIM classes, which is more standards based.

Compare some cmdlet between CIM and WMI:

There are CIM cmdlets that are directly equivalent to the WMI cmdlets:

  • Get-CimInstance
  • Invoke-CimMethod
  • Register-CimIndicationEvent
  • Remove-CimInstance
  • Set-CimInstance

You also get extra cmdlets for working with CIM classes:

  • Get-CimAssociatedInstance
  • Get-CimClass
  • New-CimInstance

The big difference between the WMI cmdlets and the CIM cmdlets is that the CIM cmdlets use WSMAN (WinRM) to connect to remote machines. In the same way that you can create PowerShell remoting sessions, you can create and manage CIM sessions by using these cmdlets:

  • Get-CimSession
  • New-CimSession
  • New-CimSessionOption
  • Remove-CimSession

Session in CIM

The best feature of the CIM cmdlets is CIM sessions. If you think back to PowerShell remoting for a second, you can send individual commands to a remote machine by using Invoke-Command, but you have to create and tear down the connection each time, which can add appreciable overhead. If you create a PowerShell remoting session, you can keep the connection open and send multiple commands to the same machines.

CIM sessions work in exactly the same way. You create a session and use it as many times as you need it before pulling it down.

Also take a look at the CDXML-based cmdlets that were introduced in Windows 8. They all have a CIMSession parameter.

Get-Command Get-NetAdapter -Syntax

Get-NetAdapter [[-Name] <string[]>] [-IncludeHidden] [-Physical] [-CimSession <CimSession[]>] [-ThrottleLimit <int>] [-AsJob] [<CommonParameters>]

Get-NetAdapter -InterfaceDescription <string[]> [-IncludeHidden] [-Physical] [-CimSession <CimSession[]>] [-ThrottleLimit <int>] [-AsJob] [<CommonParameters>]

Get-NetAdapter -InterfaceIndex <uint32[]> [-IncludeHidden] [-Physical] [-CimSession <CimSession[]>] [-ThrottleLimit <int>] [-AsJob] [<CommonParameters>]

The CDXML process automatically generates the CIMSession parameter so you don’t have to do any work to get that functionality. You can also create CIM sessions to work against systems running OMI (the open source CIM server to which Microsoft contributes), meaning you can manage Linux machines and network switches through the CIM cmdlets.

And that’s why I prefer the CIM cmdlets and would recommend that you use them instead of the WMI cmdlets.