11 min read

(For more resources related to this topic, see here.)

Windows PowerShell is a game changer in the shell scripting and automation world. This is not only because it is an object-based scripting language that is built on top of the .NET framework but also because it unifies a lot of different scripting and automation tools in one single, consistent, and dynamic engine. By leveraging the same engine and language you can deal with various amazing technologies such as Windows Management Instrumentation (WMI), Common Information Model (CIM), and Component Object Model (COM). Moreover, you can use it to build an automation interface for the applications you develop.

In this article, we will go deeper into Windows PowerShell to understand what are the different technologies that can be managed by Windows PowerShell, learn how to do it, and discover more advanced scripting techniques obtained from your current development skills.

Understanding CIM and WMI

CIM is an open standard defined by the Distributed Management Task Force (DMTF) as part of the Web-Based Enterprise Management (WBEM) initiative. CIM is used to define an extensible data model that describes, processes, and obtains the characteristic information of managed resources such as hardware components and software. CIM is a programming model that is object oriented and manufacture independent, which means that you can manage different resources from different vendors by just using the CIM standard. On the other side, WMI is a Microsoft implementation of CIM that is introduced in Windows 2000 to allow the management of all Windows software and hardware components.

CIM and WMI in Windows PowerShell

Windows PowerShell v2.0 has been shipped with a few cmdlets to support and work with WMI as a middle layer between the end user (system administrators and developers) and CIM. Later on, in Windows PowerShell v3.0, a new direct support to CIM was introduced via more cmdlets with Windows Server 2012 and Windows 8, which allows PowerShell users to directly expose the CIM schema and data model.

To retrieve the list of cmdlets for WMI and CIM, we will use the Get-Command cmdlet with the -Name parameter filtered by a wildcard and the -Type parameter, filtered by a cmdlet argument to get only the cmdlets and not functions or aliases, as shown in the following snippet:

#List all WMI available Cmdlets PS C:> Get-Command *WMI* -Type Cmdlet CommandType Name ModuleName ----------- ---- ---------- Cmdlet Get-WmiObject Microsoft.PowerShell.Management Cmdlet Invoke-WmiMethod Microsoft.PowerShell.Management Cmdlet Register-WmiEvent Microsoft.PowerShell.Management Cmdlet Remove-WmiObject Microsoft.PowerShell.Management Cmdlet Set-WmiInstance Microsoft.PowerShell.Management #List all CIM available Cmdlets PS C:> Get-Command *CIM* -Type Cmdlet CommandType Name ModuleName ----------- ---- ---------- Cmdlet Get-CimAssociatedInstance CimCmdlets Cmdlet Get-CimClass CimCmdlets Cmdlet Get-CimInstance CimCmdlets Cmdlet Get-CimSession CimCmdlets Cmdlet Invoke-CimMethod CimCmdlets Cmdlet New-CimInstance CimCmdlets Cmdlet New-CimSession CimCmdlets Cmdlet New-CimSessionOption CimCmdlets Cmdlet Register-CimIndicationEvent CimCmdlets Cmdlet Remove-CimInstance CimCmdlets Cmdlet Remove-CimSession CimCmdlets Cmdlet Set-CimInstance CimCmdlets

Now, after getting the list of both cmdlets for CIM and WMI, take a few seconds for looking at each cmdlet. Did you notice it? Yes, there are CIM cmdlets similar to WMI cmdlets, which makes sense because, as we said earlier, WMI is an implementation of CIM.

Although both the cmdlet sets look the same and show almost the same results, you will find that the CIM-related cmdlets have more parameters and there are even more cmdlets than in WMI in order to provide you with more information.

CIM and WMI represent the provided information in the form of namespaces and classes. For example, there is a class for BIOS called Win32_BIOS, and another one for the operating system called Win32_OperatingSystem. There are other classes that start with _, such as _CLASSNAME for internal operating system usage and CIM_CLASSNAME for some basic classes, but the classes that are mostly used are the ones that start with the prefix Win32_CLASSNAME.

In case you do not know the name of a class or want to discover the list of available classes in your system, you can use either the Get-WmiObject –List cmdlet or the Get-CimClass cmdlet to retrieve the same results.

#List available classes using WMI PS C:> Get-WmiObject –Class * -List #List available classes using CIM PS C:> Get-CimClass –ClassName * Win32_CurrentTime Win32_LocalTime Win32_OperatingSystem Win32_Process Win32_ComputerSystem Win32_BIOS Win32_SoftwareElement (...) #Comparing the number of classes retrieved by each cmdlet PS C:> (Get-WmiObject -List).count -eq (Get-CimClass).count True

After knowing which class you want to use, you have to create an instance of this class to get whatever information is provided by it. For this purpose, you can use either the Get-WmiObject cmdlet or the Get-CimInstance cmdlet and define the class name as a parameter.

#Get class instance using WMI PS C:> Get-WmiObject -Class Win32_BIOS #Create class instance using CIM PS C:> Get-CimInstance -ClassName Win32_BIOS SMBIOSBIOSVersion : 8BET59WW (1.39 ) Manufacturer : LENOVO Name : Default System BIOS SerialNumber : R9T081V Version : LENOVO – 1390

You can also use –Query as a parameter instead of a class name to execute a predefined WMI query written in WMI Query Language (WQL).

#Building WQL query to read from Win32_NetworkAdapter class PS C:> $Query = "Select * From Win32_NetworkAdapter Where Name like '%Intel%'" #Execute the WQL query using WMI PS C:> Get-WmiObject -Query $Query | Select DeviceID, Name #Execute the WQL query using CIM PS C:> Get-CimInstance -Query $Query | Select DeviceID, Name DeviceID Name -------- ---- 0 Intel(R) 82579LM Gigabit Network Connection 2 Intel(R) Centrino(R) Ultimate-N 6300 AGN

You can follow the same steps as in the previous example when you want to remove an instance. Use the Remove-WmiObject and Remove-CimInstance cmdlets as well as Set-WmiInstance and Set-CimInstance when you want to update an existing instance. The following simple example will show how we can use the Get-WmiObject and Remove-WmiObject cmdlets together to get a specific directory information in a WMI instance, and then delete it:

#Get a directory called "myOldBackup' $folder = Get-WmiObject -Class Win32_Directory -Filter "Name='D:\ myOldBackup'" #Remove (delete) the folder $folder | Remove-WmiObject

Other interesting cmdlets are Register-CimIndicationEvent and Register-WmiEvent; both these cmdlets allow you to trigger an action within a PowerShell scriptblock according to a predefined WMI or CIM event criteria. For example, you can trigger a notification message when the CPU utilization exceeds 85 percent or when a specific service stopped.

More reasons to adopt CIM

Well, after understanding what is WMI and CIM and exploring a few cmdlets with many similarities from both sides, you have to admit that you are getting confused and wondering why new CIM cmdlets have been introduced and why use them if WMI cmdlets were fine in the previous versions of Windows PowerShell.

To answer this question and avoid any philosophical debates, let’s discover what makes CIM an added value and feature to PowerShell using the following points:

  • It is an open standard, which means that it is not locked into the Windows operating system only, so that you can use CIM to manage other vendors and manufacturers.
  • It uses WS-Management (WS-MAN) protocol for remote management so that you can use it with any remote server or device implementing this protocol. However, WMI is used to manage only Windows over the DCOM protocol.
  • It can be used with Open Management Infrastructure (OMI) compliant devices.

    Read more about OMI from the following article:

    http://blogs.technet.com/b/windowsserver/archive/2012/06/28/open-management-infrastructure.aspx

  • It can be used to manage any computer or device with an operating system that has the CIM Object Manager (CIMOM) compliance implemented irrespective of the vendor. So, you can use CIM to manage Windows as well as non-Windows operating systems.

Working with XML

XML parsing and formatting is one of the most commonly used functionalities in application development. PowerShell provides built-in support for XML in a smart way that allows you to work with XML files easily with minimal lines of code. This is enough to make PowerShell your perfect choice for daily XML tasks and operations.

Loading XML files

There are two ways to load an XML file in PowerShell—either using the Get-Content cmdlet or using the Select-Xml cmdlet with the XPath queries.

Using the Get-Content cmdlet

In order to load and read the content of a file in PowerShell, we use the Get-Content cmdlet; this cmdlet is used to load content from text as well as XML files, which are text files written in a structured, descriptive format so that the Get-Content cmdlet can be used to load the XML files too.

#Load file content using Get-Content PS C:> Get-Content C:Employees.xml

The previous lines will load the content of the XML file as normal text. So, in order to make PowerShell understand that this is an XML file, we have to either cast the results of the Get-Content cmdlet or store the output in a strongly typed variable of XML data type, as shown in the following examples:

#results casting $employee = [xml](Get-Content D:Employees.xml) #Store results in XML variable [xml] $employees = Get-Content D:Employees.xml

The strongly typed variables, such as [xml] $employees, can be assigned only with a System.Xml.XmlDocument type of object. Otherwise, they will trigger an error.

The following code shows a sample of the employee.xml file’s structure:

<staff> <branch location="cairo"> <employee> <Name>Sherif Talaat</Name> <Role>IT</Role> </employee> </branch> </staff>

The XML file that is loaded has information about the staff members in different branches with different specialties. Now, we have the content of the file stored in a variable called $employees that can be accessed normally like any other object along with XML capabilities, as shown in the following examples:

#Access child nodes of XML documents
PS C:> $employees.staff.ChildNodes
location employee
-------- --------
cairo {Sherif Talaat, Raymond Elias}
redmond {Bill Gates, Steve Jobs}
#Get attributes information of a node
PS C:> $employees.staff.branch.Get_Attributes()
#text
-----
cairo
Redmond
#Get attributes value by Attribute name
PS C:> $employees.staff.branch. location
cairo
Redmond
#Change the value of attribute
PS C:> $employees.staff.branch[0]. location
= 'Seattle'
#Change and Modify Single node
PS C:> $employees.staff.branch.employee
Name Role
---- ----
Sherif Talaat IT
Raymond Elias Technology Specialist
PS C:> $emp = $employees.staff.branch.employee[0]
PS C:> $emp.Role = "PowerShell Guru"
PS C:> $employees.SelectNodes("//employee[Name='Sherif Talaat']")

Name Role
---- ----
Sherif Talaat PowerShell Guru
#add new node
PS C:> $newemployee = $employees.CreateElement("employee")
PS C:> $newemployee.set_InnerXML("<Name>Ahmad Mofeed</
Name>
<Role>Security Consultant</Role>")
PS C:> $employees.staff.branch[0].AppendChild($newemployee)
PS C:> $employees.staff.branch[0].employee
Name Role
---- ----
Sherif Talaat PowerShell Guru
Raymond Elias Technology Specialist
Ahmad Mofeed Security Consultant

Using the Select-Xml cmdlet

Another way to load and work with XML files is using the Select-Xml cmdlet that allows you to directly specify the XML file path along with an XPath search query to retrieve the respective node and data, as shown in the following snippet:

#Get data from XML file using XPath query PS C:> Select-Xml -Path D:Employees.xml -XPath "staff/branch/ employee" Node Path Pattern ---- ---- ------- employee D:Employees.xml staff/branch/employee employee D:Employees.xml staff/branch/employee employee D:Employees.xml staff/branch/employee

In the previous example, the Select-Xml cmdlet was used to retrieve XML nodes using the XPath search query; the result is an object of nodes with no values. To expand these nodes and enumerate their values, we have to use the Select-Object cmdlet with the -ExpandProperty parameter.

PS C:> Select-Xml -Path D:Employees.xml -XPath "staff/branch/ employee" | Select-Object -ExpandProperty Node Name Role ---- ---- Sherif Talaat IT Raymond Elias Technology Specialist Bill Gates Developer

Importing and exporting XML files

PowerShell also provides a couple of XML-related cmdlets—the Export-CliXml cmdlet to export the object(s) to an XML file and Import-CliXml to import and load the file that was previously exported by PowerShell, as shown in the following snippet:

#Export object to XML file PS C:> Get-Service | Export-Clixml D:Services.xml #Import object from XML file PS C:> Import-Clixml D:Services.xml -First 5 Status Name DisplayName ------ ---- ----------- Running AdobeARMservice Adobe Acrobat Update Service Stopped AeLookupSvc Application Experience Stopped ALG Application Layer Gateway Service Running AppIDSvc Application Identity Running Appinfo Application Information

Moreover, you also have the ConvertTo-Xml cmdlet that is similar to the Export-CliXml cmdlet, where both the cmdlets create an XML representation of one or more objects. The only difference is that the Export-CliXml cmdlet stores the XML code in a file while the ConvertTo-Xml cmdlet returns an XML object that can be used as an input to another cmdlet.

Summary

In this article, we learned how to use Windows PowerShell to work closely with WMI, COM, and XML.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here