Tip

Putting production-quality functions together in Windows PowerShell

Past articles have gone over the nuts and bolts of production-quality functions. Now we’ll put everything together and look at an example using the three components we’ve discussed: input,

    Requires Free Membership to View

output and error handling.

Before we get into the example, let’s take a moment to recap what “production-quality” really means. These are functions that are meant to run in a production environment and thus require a higher level of quality. They are generally comprised of three main design criteria:

  1. Input -- how the function accepts data
  2. Error handling -- how the function deals with error conditions
  3. Output -- data the function returns

Below is an example function called Test-Host. I use this function often and it has to be reliable both in functionality and expected output. We can’t go through it line by line, but I want to take some time to cover the key parts.

  • Documentation -- You may notice the< #...# > section near the beginning of the function. This is called inline help, and it gives the function writer the ability to provide help to the consumer of the function.

  • Parameters -- The param() statement is where we set up the parameters (input) that the function takes. In this case I tested ComputerName, TCPPort, Timeout and Property.

  • Script Flow -- The Begin script block is used for script setup and the Process script block is used to process items (objects) as they are passed in.

  • Error Handling -- Try/Catch script blocks are used to execute a branch of code and provide some feedback if the code fails.

  • Output -- If it detects an object was passed in, it does the test. If it passes, it outputs the same object. If no object is passed in, it returns the same value of ComputerName.

Below is the full function. It takes input in the form of a parameter called ComputerName, but you can specify a specific property you want to test. Once the function determines what to test, it does a simple ping or creates a TCP connection to the given port.

function Test-Host
{
   <#
      .Synopsis
         Test a host for connectivity using either WMI ping or TCP port

      .Description
         Allows you to test a host for connectivity before further processing

      .Parameter Server
         Name of the Server to Process.

      .Parameter TCPPort
         TCP Port to connect to. (default 135)

      .Parameter Timeout
         Timeout for the TCP connection (default 1 sec)

      .Parameter Property
         Name of the Property that contains the value to test.

      .Example
         cat ServerFile.txt | Test-Host | Invoke-DoSomething
         Description
         -----------
         To test a list of hosts.

      .Example
         cat ServerFile.txt | Test-Host -tcp 80 | Invoke-
         DoSomething
         Description
         -----------
         To test a list of hosts against port 80.

      .Example
         Get-ADComputer | Test-Host -property dnsHostname | Invoke-DoSomething
         Description
         -----------
         To test the output of Get-ADComputer using the dnshostname property

 

      .OUTPUTS
         System.Object

      .INPUTS
         System.String

      .Link
         Test-Port

      NAME: Test-Host
      AUTHOR: YetiCentral\bshell
      Website: www.bsonposh.com
      LASTEDIT: 02/04/2009 18:25:15
      #Requires -Version 2.0
   #>

   [CmdletBinding()]

   Param(

 

[Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true,
Mandatory=$True)]
   [string]$ComputerName,

   [Parameter()]
   [int]$TCPPort,

   [Parameter()]
   [int]$timeout=3000,

   [Parameter()]
   [string]$property

)

Begin
{

   function PingServer
   {
      Param($MyHost)
      $ErrorActionPreference = "SilentlyContinue"
      Write-Verbose " [PingServer] :: Pinging [$MyHost]"
      try
      {
         $pingresult = Get-WmiObject win32_pingstatus -f "address='$MyHost'"
         $ResultCode = $pingresult.statuscode
         Write-Verbose " [PingServer] :: Ping returned $ResultCode"
         if($ResultCode -eq 0) {$true} else {$false}
      }
      catch
      {
         Write-Verbose " [PingServer] :: Ping Failed with Error: ${error[0]}"
         $false
      }
   }

}

Process
{

   Write-Verbose " [Test-Host] :: Begin Process"
   if($ComputerName -match "(.*)(\$)$")
   {
      $ComputerName = $ComputerName -replace "(.*)(\$)$",'$1'
   }
   Write-Verbose " [Test-Host] :: ComputerName : $ComputerName"
   if($TCPPort)
   {
      Write-Verbose " [Test-Host] :: Timeout : $timeout"
      Write-Verbose " [Test-Host] :: Port : $TCPPort"
      if($property)
      {
         Write-Verbose " [Test-Host] :: Property : $Property"
         $Result = Test-Port $_.$property -tcp $TCPPort -timeout $timeout
         if($Result)
         {
            if($_){ $_ }else{ $ComputerName }
         }
      }
      else
      {
         Write-Verbose " [Test-Host] :: Running - 'Test-Port $ComputerName -tcp $TCPPort -timeout $timeout'"
         $Result = Test-Port $ComputerName -tcp $TCPPort -timeout $timeout
         if($Result)
         {
            if($_){ $_ }else{ $ComputerName }
         }
      }
   }
   else
   {
      if($property)
      {
         Write-Verbose " [Test-Host] :: Property : $Property"
         try
         {
            if(PingServer $_.$property)
            {
               if($_){ $_ }else{ $ComputerName }
            }
         }
         catch
         {
            Write-Verbose " [Test-Host] :: $($_.$property) Failed Ping"
         }
      }
      else
      {
         Write-Verbose " [Test-Host] :: Simple Ping"
         try
         {
            if(PingServer $ComputerName){$ComputerName}
         }
         catch
         {
            Write-Verbose " [Test-Host] :: $ComputerName Failed Ping"
         }
      }
   }
   Write-Verbose " [Test-Host] :: End Process"
 }
}

Miss a column? Check out our Scripting School archive.

You can follow SearchWindowsServer.com on Twitter @WindowsTT.

ABOUT THE AUTHOR
Brandon Shell has been in the IT industry since 1994. He started out as a PC tech and general fix-it guy for numerous companies. In 2007, he joined the PowerShell MVP ranks, and Shell has spent the past several years building his PowerShell knowledge and helping others build theirs.

 

This was first published in November 2010

There are Comments. Add yours.

 
TIP: Want to include a code block in your comment? Use <pre> or <code> tags around the desired text. Ex: <code>insert code</code>

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy
Sort by: OldestNewest

Forgot Password?

No problem! Submit your e-mail address below. We'll send you an email containing your password.

Your password has been sent to:

Disclaimer: Our Tips Exchange is a forum for you to share technical advice and expertise with your peers and to learn from other enterprise IT professionals. TechTarget provides the infrastructure to facilitate this sharing of information. However, we cannot guarantee the accuracy or validity of the material submitted. You agree that your use of the Ask The Expert services and your reliance on any questions, answers, information or other materials received through this Web site is at your own risk.