Exploring .NET objects

An object is nothing but a combination of methods and properties in PowerShell. Using Windows PowerShell, we can store a reference to an object to a variable and use it in the current shell as required.

We discussed in Chapter 1, Getting Started with Windows PowerShell that PowerShell takes advantage of the underlying .NET framework. So, the objects are a representation of the parts and actions to use it. An object is a combination of the properties and methods (Objects = Properties + Methods).

For example, a Windows service object has properties and methods. The properties are Get and Set, and the methods are invoked to perform a meaningful operation.

Consider the following image:

Exploring .NET objects

Creating .NET objects

We have discussed objects in a few of the preceding examples as well. In this section, we will explore the .NET objects in PowerShell. In order to create a .NET object, we will use the same New-Object cmdlet, but instead of the COM object, we will use different types of objects.

To create a .NET object for the system version, we will use the following code:

$Version = New-Object -TypeName System.Version -ArgumentList 1.2.3.4
$Version

The output is illustrated in the following image:

Creating .NET objects

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

  • 1: Here, we created a variable $Version
  • 2: Here, we used the New-Object cmdlet
  • 3: Here, we are using the parameter –TypeName to call the .NET framework class
  • 4: Here, we are calling the System.Version .NET framework class
  • 5: Here, we are using –ArgumentList to pass values to the constructor of the class
  • 6: The passed values are 1.2.3.4.

As we have discussed a little about typecasting in the previous topics, we can do the same here as well. Run the following command:

[System.Version]"1.2.3.4"

The result is the same, as shown in the following image:

Creating .NET objects

Extending .NET objects for Administrations and Development tasks

Using PowerShell, we can extend the instance of the .NET object. To do this, we will use the Add-member cmdlet. In the following example, we will discuss extending the System.String class:

$string = New-Object -TypeName System.String -ArgumentList "PowerShell Rocks!"
($string).GetType()

The output of the code we just saw is illustrated in the following image:

Extending .NET objects for Administrations and Development tasks

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

  • 1: In the above code, we use GetType() method to explore the type name. It's a string.
  • 2: Here, the argument passed for the constructor of System.String class is PowerShell Rocks!
  • 3: Here, the value returned is String
  • 4: The base objects in System.Object (Note: If we do $var = 123 ; $var.GetType() the base objects returns System.Value). In the above code we have created a String object. So, the base type shows the ultimate base class of all classes in the .NET Framework

Now, let's add NoteProperty. This will return the total character counts from the value passed through, which is ArgumentList. Run the following command:

$string = New-Object -TypeName System.String -ArgumentList "PowerShell Rocks!"
$String | Add-Member -MemberType NoteProperty "TotalCharacters" -Value $string.Length
$string.TotalCharacters

The output is illustrated in the following image:

Extending .NET objects for Administrations and Development tasks

Let's consider another example where we concatenate the ScriptMethod object to a string object. Run the following command:

$string = New-Object -TypeName System.String -ArgumentList "PowerShell Rocks!"
$String | Add-Member -MemberType ScriptMethod -Name "ConcatCustom" -Value {[String]::Concat($this , " Demo")}
$string.ConcatCustom()

The preceding code appended the Demo string to the ArgumentList string, PowerShell Rocks!.

The output is illustrated in the following image:

Extending .NET objects for Administrations and Development tasks

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

  • 1: This shows that the member type of the Add-Member cmdlet is ScriptMethod
  • 2: Here, I named the script as CustomConcat just for demo purposes—You can choose any custom name
  • 3: Here, the Value parameter defines the script
  • 4: Here, we used the [String]::Concat method just for simple demo purposes
  • 5: Here, we see that the Concat method accepts two string parameters (string1, string2)
  • 6: Here, we can see that the value parameter accepts the $this automatic variable as well
  • 7: Here, we see that Demo is a string we need to concatenate
  • 8: Here, we invoke our script method
  • 9: Here, we see the output as PowerShell Rocks! Demo

Extending the .NET Framework types

Using Windows PowerShell, we can define a Windows .NET Framework class in the session and instantiate the object using New-Object. PowerShell allows us to use the inline C# code using a here-string. To define a here-string in Windows PowerShell, we should use @" and close it with "@—anything between these marks is a here-string, as shown in the following snippet:

@"
"here strings"
"@

From Windows PowerShell 5.0 onward, we can write the class in Windows PowerShell. The Class keyword is supported only in PowerShell version 5.0. For now, let's take a look at how the Add-Type cmdlet works. In the following example, we will take a look at code with the inline C# code:

$sourcecode = @"
public class Calculator
{
  public static int Add(int a, int b)
  {
    return (a + b);
  }
}
"@
Add-Type -TypeDefinition $sourcecode
[Calculator]

The output is illustrated in the following image:

Extending the .NET Framework types

Now, we can call the Add method directly without using the New-Object cmdlet. Run the following command:

$sourcecode = @"
public class Calculator
{
  public static int Add(int a, int b)
  {
    return (a + b);
  }
}
"@
Add-Type -TypeDefinition $sourcecode
[Calculator]::Add(10,5)

PowerShell allows us to execute the static methods of a class directly in PowerShell. System.Math has a static method called sqrt, which can be used as shown in the following command:

[System.Math]::Sqrt(4)

In the following example, we will create a simple class using the Class keyword:

Class Demo
{
  #Properties
  [string]$FirstName = "Chen"
  [string]$surname = "V"
  #Methods - This will print the values and just for demo
  [string]GetInformation() {
    return "$($this.FirstName) $($this.surname)"
  }
}

Following is the alternate method to instantiate the class:

  • We have used the keyword Class and named it as Demo
  • $FirstName and $surname are properties
  • GetInformation is a method and $this is an automatic variable used
  • Used $var variable and instantiating the class using New-Object cmdlet. With the same code the class can instantiated using $var = [Demo]::new();$var.GetInformation()

The output is shown in the following image:

Extending the .NET Framework types

Let's explore the property, as shown in the following image:

Extending the .NET Framework types

The class Demo we created in the preceding section has properties and methods, but we practically don't need the GetInformation method because it just prints the property values. Let's create another class with the SetInformation method which updates the property values. Run the following command:

Class Demo
{
  #Properties
  [string]$FirstName = "Chen"
  [string]$surname = "V"
  #Methods - This will print the values and just for demo
  GetInformation() {
    $this.FirstName
    $this.surname
  }
  SetInformation([string]$fn,[string]$sn) {
  $this.FirstName = $fn
  $this.surname = $sn 
  }
}
$var = New-Object -TypeName Demo
$var.SetInformation("Chendrayan" , "Venkatesan")
$var

The preceding code returns the following output:

Extending the .NET Framework types

We will cover more information about the classes in the Exploring Windows PowerShell 5.0 section.

Building advanced scripts and modules

Windows PowerShell scripting is used imperatively to perform complex operations using cmdlets. Windows PowerShell supports variables, functions, branching, loops, structured exception handling and, as we all know, .NET integration.

The PowerShell script file has a PS1 extension. For example, let's save the following file as PS1 and execute it:

Function Get-Information
{
  (Get-Service).Where({$_.Status -eq 'Stopped'})
}
Get-Information

The preceding script is a very basic code to retrieve all the running services. Consider the following image:

Building advanced scripts and modules

Before taking a look at the advanced functions, let's consider the fundamentals of PowerShell scripting.

A PS1 file is nothing but a text file that contains a sequence of PowerShell cmdlets to perform certain complex tasks. Before you execute a PowerShell script, ensure that the script execution policy is set as required. There are different types of execution policies; to know them, simply execute the following help cmdlet:

help about_Execution_Policies -Detailed

Before creating PowerShell scripts, ensure that you plan and document the synopsis. Using the Measure-Command cmdlet, ensure that you optimize the performance of the code as required.

Now, let's take a look at the advanced function and save it as PS1 file. For this demo, I have used the PowerShell ISE, which has a snippet for advanced functions and advanced function complete.

The structure of the advanced function is shown in the following image:

Building advanced scripts and modules

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

  • 1: This is a comment block
  • 2: Using synopsis, description, examples, and notes makes the script readable and easy to understand
  • 3: Name of the function—always a Verb-Noun Combination is the best practice
  • 4: The CmdletBinding attribute is an attribute of functions, which makes a function work similarly to a compiled cmdlet that is written in C#
  • 5: Here, the param block is used to define parameters
  • 6: Here, the begin block is used to provide optional onetime pre-processing
  • 7: Here, the process block is used to provide record by record processing
  • 8: Here, the end block is used to provide optional one time post-processing

Let's take the example of a PowerShell script that retrieves system information and saves the output as an HTML file, which uses the CSS style sheet. Run the following code:

<#
 .SYNOPSIS
  Windows Machine Inventory Using PowerShell.
 .DESCRIPTION
  This script is to document the Windows machine. This script will work only for Local Machine.
 .EXAMPLE
  PS C:> .System_Inventory.PS1
 .OUTPUTS
  HTML File OutPut ReportDate , General Information , BIOS Information etc.
#>
#Set-ExecutionPolicy RemoteSigned -ErrorAction SilentlyContinue
$UserName = (Get-Item  env:username).Value
$ComputerName = (Get-Item env:Computername).Value
$filepath = (Get-ChildItem env:userprofile).value
Add-Content  "$Filepathstyle.CSS"  -Value " body {
  font-family:Calibri;
  font-size:10pt;
}
th { 
  background-color:black;
  color:white;
}
td {
  background-color:#19fff0;
  color:black;
}"
Write-Host "CSS File Created Successfully... Executing Inventory Report!!! Please Wait !!!" -ForegroundColor Yellow
#ReportDate
$ReportDate = Get-Date | Select -Property DateTime |ConvertTo-Html -Fragment
#General Information
$ComputerSystem = Get-WmiObject -Class Win32_ComputerSystem | 
Select -Property Model , Manufacturer , Description , PrimaryOwnerName , SystemType |ConvertTo-Html -Fragment
#Boot Configuration
$BootConfiguration = Get-WmiObject -Class Win32_BootConfiguration |
Select -Property Name , ConfigurationPath | ConvertTo-Html -Fragment 
#BIOS Information
$BIOS = Get-WmiObject -Class Win32_BIOS | Select -Property PSComputerName , Manufacturer , Version | ConvertTo-Html -Fragment
#Operating System Information
$OS = Get-WmiObject -Class Win32_OperatingSystem | Select -Property Caption , CSDVersion , OSArchitecture , OSLanguage | ConvertTo-Html -Fragment
#Time Zone Information
$TimeZone = Get-WmiObject -Class Win32_TimeZone | Select Caption , StandardName |
ConvertTo-Html -Fragment
#Logical Disk Information
$Disk = Get-WmiObject -Class Win32_LogicalDisk -Filter DriveType=3 | 
Select SystemName , DeviceID , @{Name="size(GB)";Expression={"{0:N1}" -f($_.size/1gb)}}, @{Name="freespace(GB)";Expression={"{0:N1}" -f($_.freespace/1gb)}} |
ConvertTo-Html -Fragment
#CPU Information
$SystemProcessor = Get-WmiObject -Class Win32_Processor  | 
Select SystemName , Name , MaxClockSpeed , Manufacturer , status |ConvertTo-Html -Fragment
#Memory Information
$PhysicalMemory = Get-WmiObject -Class Win32_PhysicalMemory |
Select -Property Tag , SerialNumber , PartNumber , Manufacturer , DeviceLocator , @{Name="Capacity(GB)";Expression={"{0:N1}" -f ($_.Capacity/1GB)}} | ConvertTo-Html -Fragment
#Software Inventory
$Software = Get-WmiObject -Class Win32_Product |
Select Name , Vendor , Version , Caption | ConvertTo-Html -Fragment 
ConvertTo-Html -Body "<font color = blue><H4><B>Report Executed On</B></H4></font>$ReportDate
<font color = blue><H4><B>General Information</B></H4></font>$ComputerSystem
<font color = blue><H4><B>Boot Configuration</B></H4></font>$BootConfiguration
<font color = blue><H4><B>BIOS Information</B></H4></font>$BIOS
<font color = blue><H4><B>Operating System Information</B></H4></font>$OS
<font color = blue><H4><B>Time Zone Information</B></H4></font>$TimeZone
<font color = blue><H4><B>Disk Information</B></H4></font>$Disk
<font color = blue><H4><B>Processor Information</B></H4></font>$SystemProcessor
<font color = blue><H4><B>Memory Information</B></H4></font>$PhysicalMemory
<font color = blue><H4><B>Software Inventory</B></H4></font>$Software" -CssUri  "$filepathstyle.CSS" -Title "Server Inventory" | Out-File "$FilePath$ComputerName.html"
Write-Host "Script Execution Completed" -ForegroundColor Yellow
Invoke-Item -Path "$FilePath$ComputerName.html"

Note that the preceding code is not a function—it's just a script. Save this as PS1 and execute the script.

The sample output is shown in the following image:

Building advanced scripts and modules

The script has the following elements:

  • Comment block
  • Parameter declared for computer name and file path
  • Creates CSS file in C: drive for styling
  • Report executed date
  • General system information
  • Boot configuration information
  • BIOS information
  • OS information
  • Time zone settings
  • Logical disk information
  • CPU information
  • Memory information
  • Software inventory
  • Converts to HTML and outputs in HTML file
  • Invoke the HTML file in default browser

Consider the following image:

Building advanced scripts and modules

Let's take an example where we will create an advanced function. Advanced functions include help, parameters, accepting pipelines, and so on.

Note

Note that, to do this easily, you can open PowerShell ISE, press CTRL + J, and choose the Cmdlet (advanced function).

Perform the following steps:

  1. Write a simple help block for a function:
    <#
    .Synopsis
      A script to retrieve OS information.
    .DESCRIPTION
      This PowerShell script will retrieve OS information like Name , OS Architecture, Serial Number and Last Bootup time.
      This script use CIM instance.
    .EXAMPLE
      Get-OSInformation -ComputerName localhost
    .EXAMPLE
      Get-OSInformation -ComputerName localhost , remotecomputer
    .EXAMPLE
      localhost , remotecomputer | Get-OSInformation
    #>
    

    The help block has synopsis, description, and three examples.

  2. Create a function using the keyword function and name it in the Verb-Noun form. In our example, this is Get-OSInformation, as shown in the following command:
    function Get-OSInformation { #Code goes here}
    
  3. Use CmdletBinding. Take a look at the following code:
    [CmdletBinding(ConfirmImpact = 'Low', HelpUri = 'http://chen.about-powershell.com')]
    

    I have set the ConfirmImpact to low, and I have used HelpUri from my blog post—just for this example. You can use any valid site that has some information. You may wonder, why do we use CmdletBinding? It is to ease our function creation and to make additional validation for our parameters. For more information execute help about_Functions_CmdletBindingAttribute

  4. Declare the parameters. In this example, we will use a single parameter, as shown in the following code:
         Param
        (
            # Param1 help description
            [Parameter(Mandatory=$true,
                HelpMessage = "Please enter valid host name",
                ValueFromPipelineByPropertyName=$true,
                ValueFromPipeline = $true,
                Position=0)]
            [String[]]$ComputerName
        )
    

    Use the following code:

        Begin
        {
            #Intentionally left blank
        }
        Process
        {
            foreach($computer in $ComputerName)
            {
                $params = @{'ComputerName' = $Computer
                    'Class' = 'CIM_OperatingSystem'}
                Get-CimInstance @Params | 
                Select Caption , OSArchitecture , SerialNumber , LastBootUptime
            }
        }
        End
        {
            #Intentionally left blank
        }
    
  5. Save the PS1 file in the desired location and call it using a dot sourcing operator. Take a look at the following image:
    Building advanced scripts and modules

Now, let's call the function using Get-OSInformation by skipping the mandatory parameter, as shown in the following image:

Building advanced scripts and modules

Type !? to see the help text, as shown in the following image:

Building advanced scripts and modules

That's cool! Now, we can see the help message in the parameter block.

Using the help command, we can obtain more information about the command.

The output is illustrated in the following image:

Building advanced scripts and modules

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

  • 1: Name of the command appears here.
  • 2: Whatever we enter in the synopsis appears here.
  • 3: Here, syntax appears automatically and it shows the datatype as well.
  • 4: Description is again customized—what we entered in the description section appears here.
  • 5: RELATED LINKS—appears by default if you have included .LINK in the comment block. Used for external web site links.
  • 6: REMARKS—appears by default.

Note that here, the help command will not show the input and output parameters, and so on.

Use the help Get-OSInformation –Full command to explore more.

We used the blog post URL in the help message URI in cmdlet binding; so, to make use of this, we can use the following code:

help Get-OSInformation -Online

The complete code is available here:

<#
.Synopsis
  A script to retrieve OS information.
.DESCRIPTION
  This PowerShell script will retrieve OS information like Name , OS Architecture, Serial Number and Last Bootup time.
  This script use CIM instance.
.EXAMPLE
  Get-OSInformation -ComputerName localhost
.EXAMPLE
  Get-OSInformation -ComputerName localhost , remotecomputer
.EXAMPLE
  localhost , remotecomputer | Get-OSInformation
#>
function Get-OSInformation {
  [CmdletBinding(ConfirmImpact = 'Low', HelpUri = 'http://chen.about-powershell.com')]
Param(
# Param1 help description
[Parameter(Mandatory=$true,
    HelpMessage = "Please enter valid host name",
    ValueFromPipelineByPropertyName=$true,
    ValueFromPipeline = $true,
    Position=0)]
    [String[]]$ComputerName)
Begin{<#Intentionally left blank#>}
    Process
    {
        foreach($computer in $ComputerName)
        {
            $params = @{'ComputerName' = $Computer
                'Class' = 'CIM_OperatingSystem'}
            Get-CimInstance @Params | 
            Select Caption , OSArchitecture , SerialNumber , LastBootUptime
        }
    }
    End
    {
        #Intentionally left blank
    }
}

In this section, we will explore Windows PowerShell modules.

Windows PowerShell modules are packages that contain the PowerShell commands. Using modules, we can organize our commands and share them with others.

In this example, we will create a simple module as a demo and this will be a script module. We will discuss all types of modules and demos in the Understanding PowerShell Modules section.

A script module is a file (.psm1) that contains valid Windows PowerShell code. Script developers and administrators can use this type of module to create modules whose members include functions, variables, and more.

In this example, we have two functions—Get-OSInformation and Get-DiskInformation. Let's save this as Sysinformation.PSM1 in the temp folder for now.

Function Get-SystemInformation
{
    param(
    [Parameter(Mandatory = $true)]
    [String]
    $ComputerName
    )
    $OS = Get-WmiObject -Class Win32_OperatingSystem
    $BIOS = Get-WmiObject -Class Win32_Bios
    $CS = Get-WmiObject -Class Win32_ComputerSystem
    $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

Now, we need to import a module; to do this we need to use the Import-Module command. In the following code the –Verbose and –Force parameters are used for a clear output. Take a look at the following image:

Building advanced scripts and modules

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

  • 1: Here, we use the Import-Module cmdlet to import the script module we created. The module name is SysInformation.PSM1.
  • 2: Here, we explicitly mention the path—we have saved the script in C:Temp.
  • 3: –Verbose is used to see the verbose data.
  • 4: –Force parameter is used to remove the existing script and import it newly.
  • 5: Since we use the force parameter we can see here that the function is being removed.
  • 6: Here, the function is being imported again.

Now, let's call the functions as cmdlet. Take a look at the following image:

Building advanced scripts and modules

Note

Note that each Get-OSInformation and Get-DiskInformation cmdlet has its own help information.

..................Content has been hidden....................

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