Chapter 2. Unleashing Development Skills Using Windows PowerShell 5.0

Windows PowerShell 5.0 is a dynamic and object-oriented scripting language. Compared to any other scripting language, it provides more benefits, such as reliability, security, managed code environments, and so on. Windows PowerShell has a strong connection with Windows Management Instrumentation (WMI), Common Information Model (CIM), Extensible Markup Language (XML), and so on. Using this, we can develop solutions to automate our tasks.

PowerShell has the ability to manage different technologies. Using the PowerShell API, we can manage custom-built applications as well.

In this section, we will cover the following topics:

  • Basics of WMI and CIM
  • Exploring the XML and COM automation
  • Exploring .NET objects for admins and development tasks
  • Building advanced scripts and modules
  • An insight into Windows PowerShell 5.0
  • Script debugging

Basics of WMI and CIM

WMI—Windows Management Instrumentation—is the Microsoft implementation of WBEM—Web Based Enterprise Management—which allows us to access management information from any environment. PowerShell makes access to WMI easy and consistently deliverable using an object-based technique.

Let's explore a few PowerShell cmdlets of WMI.

WMI is a part of the Microsoft.PowerShell.Management module. You can run the following command to explore the WMI cmdlets:

Get-Command -Module Microsoft.PowerShell.Management -Name '*WMI*'

The output is illustrated in the following image:

Basics of WMI and CIM

There are many tools available to explore all the WMI classes available in the WMI repository. You can use the following links to do so:

https://wmie.codeplex.com/

https://www.sapien.com/software/wmiexplorer

Using these tools, we can explore and view the classes, instances, properties, and qualifiers easily. It's a GUI tool, so it makes our job easy as well. As we are focusing more on PowerShell, let's do it the PowerShell way, on the fly and explore.

The Get-WmiObject cmdlet has a switch parameter to list all the classes. The Get-WmiObject –List command will retrieve all the classes from the RootCIMV2 namespace by default. However, we can explicitly mention the namespace using the NameSpace parameter to identify the specified WMI class location, as shown in the following command:

#Retrieves WMI Class from RootSecurity NameSpace
Get-WmiObject -List -Namespace 'RootSecurity'
#Retrieves WMI Class from RootCIMV2 - Default
Get-WmiObject -List

To know more about WMI cmdlets, use the help about_WMI_Cmdlets command.

PowerShell supports the WMIClass type accelerators, which is a shortcut for using .NET classes in PowerShell.

  • [WMI]: This is the type accelerator for the ManagementObject class
  • [WMIClass]: This is the type accelerator for the ManagementClass class
  • [WMISearcher]: This is the type accelerator for the ManagementObjectSearcher class

These make PowerShell richer and more useful; therefore, system administrators can use WMI in PowerShell very easily.

Let's query a service named WinRM using the WMI type accelerator. Run the following command:

[wmi]"rootcimv2:Win32_Service.Name='WinRM'"
Basics of WMI and CIM

The same can be achieved using the following Windows PowerShell commands:

Get-WmiObject -Class Win32_Service -Filter "Name='WinRM'"
Get-WmiObject -Class Win32_Service | ? {$_.Name -eq 'WinRM'}
(Get-WmiObject -Class Win32_Service).Where({$_.Name -eq 'WinRM'})

All of the preceding commands provide the same result, and it depends upon the usage and optimization. The Get-WMIObject cmdlet has a parameter named Query, which allows us to use WMI Query Language (WQL), as in the following command:

Get-WmiObject -Query "Select * from Win32_Service where Name='WinRM'"
Basics of WMI and CIM

Using the WMIClass type accelerator, we can invoke any method easily, as shown in the following command:

$Obj = [wmiclass]"Win32_Process"
$Obj.Create('NotePad.exe')

The output of this command is as shown in the following image:

Basics of WMI and CIM

The WMI provider consists of the Managed Object Format (MOF) file, which defines the data, classes, and associated events. Using the WMIClass type accelerator method, it's possible to explore the MOF file. Consider the following commands:

$Obj = [wmiclass]"Win32_OperatingSystem"
$Obj.GetText('MOF')

The preceding commands would output the MOF file as shown in the following image—you can use the Out-GridView cmdlet for look and feel:

Basics of WMI and CIM

The same MOF file can be found at $ENV:WindirSYSTEM32WBEM. Use the following command:

Get-ChildItem  C:windowsSystem32wbem -Filter *.MOF

Windows PowerShell has a command named Invoke-WMIMethod, which is used to invoke methods without using type accelerators.

Note that in the following code, we have used | Out-Null, which deletes the output instead of sending it to the pipeline:

Invoke-WmiMethod -Class Win32_process -Name Create -ArgumentList Notepad.exe | Out-Null

This is similar to casting to Void type, as shown in the following command:

[Void](Invoke-WmiMethod -Class Win32_process -Name Create -ArgumentList Notepad.exe)
Basics of WMI and CIM

Using the WMISearcher type accelerator, we can explore the WMI data. Now, let's try the following code:

$Obj = [wmisearcher]"Select * from Win32_Process Where Name = 'Notepad.exe'"
$Obj
Basics of WMI and CIM

Let's consider what this is. This outputs Scope, Query, Options, Site, and Container, which are the properties. To get the result collections we need to invoke GetMethod() method.

$Obj = [wmisearcher]"Select * from Win32_Process Where Name = 'Notepad.exe'"
$Obj.Get()

Using pipelines, we can select the properties we need to view, as in the following command:

$Obj = [wmisearcher]"Select * from Win32_Process Where Name = 'Notepad.exe'"
$Obj.Get() | Select Caption , ExecutablePath , UserModeTime

The output is illustrated in the following image:

Basics of WMI and CIM

The points marked in the figure are explained in the following list:

  • 1: Here, we have used the pipeline to select the information required
  • 2: This shows the output Caption, ExecutablePath, and UserModeTime

Let's consider a demo of a tiny PowerShell function using WMI.

We will need to retrieve the BIOS, computer system, and operating system information from the given servers in the environment.

We will use the WIN32_BIOS, Win32_ComputerSystem, and Win32_OperatingSystem classes to get the information.

Execute the following code:

Function Get-SystemInformation {
  param(
  [parameter(Mandatory = $true)]
  [String]$computername
  )
  $OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername
  $BIOS = Get-WmiObject -Class Win32_BIOS -ComputerName $computername
  $CS = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computername
  $properties = New-Object psobject -Property @{
    "OSName" = $os.Caption
    "ServicePack" = $os.CSDVersion
    "SerialNumber" = $BIOS.SerialNumber
    "Manufacturer" = $BIOS.Manufacturer
    "Bootupstate" = $cs.BootupState
  }
  $properties
}
Get-SystemInformation -computername localhost
Basics of WMI and CIM

Let's consider how this works. Perform the following steps:

  1. Use the Function keyword to create a function.
  2. You can name the function Get-SystemInformation as this is a friendly name, but ensure that you follow the verb-noun combination for easy understanding.
  3. Use the Param block to declare a variable.
  4. Declare a variable and name it $ComputerName (For now, we will use a localhost).
  5. Use Win32_BIOS, Win32_ComputerSystem, and Win32_OperatingSystem and assign each a variable.
  6. Create an object using the PSObject class and collect all information in $Properties object.
  7. Get the required properties.
  8. Output the result.
  9. Call the function.

The output is illustrated in the following image:

Basics of WMI and CIM

WMI uses Distributed COM (DCOM) to connect to a remote computer. However, in certain environments, this may be blocked by a firewall. In this scenario, we can retrieve the information using the PowerShell remoting feature or using the WSMan object.

To explore the WSMan commands, you can execute the following command:

Get-Command -Module Microsoft.WSMan.Management

The output is illustrated in the following image:

Basics of WMI and CIM

As we are discussing the basics of WMI here, we are not covering all the topics. However, we will discuss more about WMI and CIM in further topics.

CIM is defined by Distributed Management Task Force (DMTF) and is an object-oriented data model. In WMI, developers can use CIM to create classes. Using CIM, it's easy to manage the different elements of an environment.

CIM cmdlets are introduced in PowerShell 3.0, and these are vendor independent. Considering the recent Cloud operating system, we will have to work with different manufacturers. So, using CIM is the best option because WMI is Windows-based; it implements the DMTF standards in CIM and also allows us to query non-Windows operating systems.

The advantages of CIM in PowerShell are its usability and ability to run quite faster than WMI. PowerShell facilities such as tab completion make CIM cmdlets very rich. In other words, CIM is a superset of WMI.

To know the available CIM cmdlets, we can simply run the following code:

(Get-Command -Noun CIM*).Name

It will return the following output:

Get-CimAssociatedInstance
Get-CimClass
Get-CimInstance
Get-CimSession
Invoke-CimMethod
New-CimInstance
New-CimSession
New-CimSessionOption
Register-CimIndicationEvent
Remove-CimInstance
Remove-CimSession
Set-CimInstance

Let's query the basic OS and BIOS information as follows:

Function Get-SystemInformation {
  param(
  [Parameter(Mandatory = $true,ValueFromPipeline = $true)]
  [string[]]$ComputerName
  )
  Begin{}
  Process{
    foreach($computer in $ComputerName) {
      $OS = Get-CimInstance -ClassName CIM_OperatingSystem -ComputerName $computer
      $BIOS = Get-CimInstance -ClassName Win32_BIOS -ComputerName $computer
      $props = New-Object psobject -Property @{
        OSName = $os.Caption
        ServicePack = $OS.CSDVersion
        BIOSSerialNumber = $BIOS.SerialNumber
        BIOSReleaseDate = $BIOS.ReleaseDate
      }
    }
    $props
  }
  End{}
}
#Demo
"localhost" ,"Localhost" | %{
  Get-SystemInformation -ComputerName $_ 
}

Note that every time you run the function, the output order is different. To get an ordered output, we can make a minor change in the code, as shown in the following:

$props = [Ordered] @{
  OSName = $os.Caption
  ServicePack = $OS.CSDVersion
  BIOSSerialNumber = $BIOS.SerialNumber
  BIOSReleaseDate = $BIOS.ReleaseDate
}
New-Object psobject -Property $props

The preceding code returns an ordered output, as shown in the following image:

Basics of WMI and CIM

The points marked in the figure are explained in the following list:

  • 1: OSName lists the names of operating systems
  • 2: ServicePack gives service pack information
  • 3: BIOSSerialNumber gives BIOS serial number information
  • 4: BIOSReleaseDate lists the release date of operating systems

What does [Ordered] do here? It simply makes an ordered dictionary. Let's take a look at another example of this.

The following code creates a hash table; the output order will be random:

$props = @{A='1'
  B='2'
  C='3'
}

To identify the type name, we use the GetType() method, which returns a hash table as names. Following is the command:

$props.GetType()

The following code will return an output in the same order (A, B, and C). This is an ordered dictionary type:

$props = [Ordered]@{A='1'
  B='2'
  C='3'
}

CIM cmdlets are introduced in PowerShell 3.0; so, before using CIM to query devices, we should ensure that it complies with the CIM and WSMan standards defined by DMTF. You may wonder, how can we use CIM while querying in a mixed environment, where we may have Windows Server 2012 and 2008 R2 with PowerShell 2.0? The CIM class works on the devices that have PowerShell version 3.0. What happens if we try to use the Invoke-Command cmdlet? It will fail with an error message, 'Get-CimInstance' is not recognized as the name of a cmdlet, function, script file, or operable program.

The solution is to use a CIM session. Let's take a look at how to use the CIM session in this example. Execute the following code:

Test-WSMan -ComputerName RemoteServer

The output is illustrated in the following image—the version used here is 2.0:

Basics of WMI and CIM

All we need to know in the two CIM cmdlets are their parameters, which are as follows:

  • The New-CimSessionOption cmdlet
  • The Get-CimInstance cmdlet

Execute the following code:

$dcom = New-CimSessionOption -Protocol Dcom
$Remote = New-CimSession -ComputerName 'RemoteServer' -SessionOption $dcom
(Get-CimInstance -CimSession $Remote -ClassName CIM_OperatingSystem).InstallDate

Let's take a look at how this works.

We used the DCOM protocol, which is New-CimSessionOption, and assigned it to a $dcom variable. Then, we used the New-CIMSession cmdlet to create a session with the -SessionOption parameter (we used $dcom, which is nothing but a DComSessionOptions type). Finally, we used the Get-CimInstance cmdlet and consumed $Remote, which is the CimSession type, with the DCOM protocol.

To remove the CIM session, we will simply use the following snippet:

Get-CimSession | Remove-CimSession

The benefits of using CIM cmdlets are as follows:

  • There are loads of improvements while working with WMI association
  • We can use Get-CimClass to explore a WMI class
  • CIM session is beneficial to the query devices included with version 2.0
  • There are no more DCOM errors
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset