Home > Sample chapters

Working with Functions in Windows PowerShell

Using a type constraint in a function

When you are accepting parameters for a function, it might be important to use a type constraint to ensure that the function receives the correct type of data. To do this, you place the name of the type you want inside brackets in front of the input parameter. This constrains the data type and prevents the entry of an incorrect type of data. Frequently used type accelerators are shown in Table 6-2.

TABLE 6-2 Data type aliases

Alias

Type

[int]

32-bit signed integer

[long]

64-bit signed integer

[string]

Fixed-length string of Unicode characters

[char]

Unicode 16-bit character

[bool]

True/false value

[byte]

8-bit unsigned integer

[double]

Double-precision 64-bit floating-point number

[decimal]

128-bit decimal value

[single]

Single-precision 32-bit floating-point number

[array]

Array of values

[xml]

XML object

[hashtable]

Hashtable object (similar to a dictionary object)

In the Resolve-ZipCode function, which is shown in the following Resolve-ZipCode.ps1 script, the $zip input parameter is constrained to allow only a 32-bit signed integer for input. (Obviously, the [int] type constraint would eliminate most of the world’s postal codes, but the web service the script uses only resolves US-based postal codes, so it is a good addition to the function.)

In the Resolve-ZipCode function, the first thing that is done is to use a string that points to the WSDL (Web Services Description Language) for the web service. Next, the New-WebServiceProxy cmdlet is used to create a new web service proxy for the ZipCode service. The WSDL for the ZipCode service defines a method called the GetInfoByZip method. It will accept a standard US-based postal code. The results are displayed as a table. The Resolve-ZipCode.ps1 script is shown here.

Resolve-ZipCode.ps1

#Requires -Version 5.0
Function Resolve-ZipCode([int]$zip)
{
 $URI = "http://www.webservicex.net/uszip.asmx?WSDL"
 $zipProxy = New-WebServiceProxy -uri $URI -namespace WebServiceProxy -class ZipClass
 $zipProxy.getinfobyzip($zip).table
} #end Get-ZipCode

Resolve-ZipCode 28273

When you use a type constraint on an input parameter, any deviation from the expected data type will generate an error similar to the one shown here.

Resolve-ZipCode : Cannot process argument transformation on parameter 'zip'. Cannot convert
value "COW" to type "System
.Int32". Error: "Input string was not in a correct format."
At C:\Users\ed\AppData\Local\Temp\tmp3351.tmp.ps1:22 char:16
+ Resolve-ZipCode <<<<  "COW"
    + CategoryInfo          : InvalidData: (:) [Resolve-ZipCode],
ParameterBindin...mationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Resolve-ZipCode

Needless to say, such an error could be distracting to the users of the function. One way to handle the problem of confusing error messages is to use the Trap keyword. In the DemoTrapSystemException.ps1 script, the My-Test function uses [int] to constrain the $myinput variable to accept only a 32-bit unsigned integer for input. If such an integer is received by the function when it is called, the function will return the string It worked. If the function receives a string for input, an error will be raised, similar to the one shown previously.

Rather than display a raw error message, which most users and many IT professionals find confusing, it is a best practice to suppress the display of the error message, and perhaps inform the user that an error condition has occurred and provide more meaningful and direct information that the user can then relay to the help desk. Many times, IT departments will display such an error message, complete with either a local telephone number for the appropriate help desk, or even a link to an internal webpage that provides detailed troubleshooting and corrective steps the user can perform. You could even provide a webpage that hosted a script that the user could run to fix the problem. This is similar to the “Fix it for me” webpages Microsoft introduced.

When an instance of a System.SystemException class occurs (when a system exception occurs), the Trap statement will trap the error, rather than allowing it to display the error information on the screen. If you were to query the $error variable, you would find that the error had in fact occurred and was actually received by the error record. You would also have access to the ErrorRecord class via the $_ automatic variable, which means that the error record has been passed along the pipeline. This gives you the ability to build a rich error-handling solution. In this example, the string error trapped is displayed, and the Continue statement is used to continue the script execution on the next line of code. In this example, the next line of code that is executed is the After the error string. When the DemoTrapSystemException.ps1 script is run, the following output is shown.

error trapped
After the error

The complete DemoTrapSystemException.ps1 script is shown here.

DemoTrapSystemException.ps1

Function My-Test([int]$myinput)
{

 "It worked"
} #End my-test function
# *** Entry Point to Script ***

Trap [SystemException] { "error trapped" ; continue }
My-Test -myinput "string"
"After the error"