Executive Summary:
Like any scripting language, Windows PowerShell lets you create functions. You can make functions as simple or as complex as necessary. In this lesson, you'll learn how to create your own functions, including how to incorporate named parameters and how to give those parameters default values. You'll also learn how to work with your functions' output so you can use it in PowerShell scripts.

Like any scripting language, Windows PowerShell lets you create functions that you can reference within PowerShell statements. A function is basically a named block of code. When you call the function name, the script block within that function runs. You can include any PowerShell statements within the script block, and you can add input parameters so you can use the same function in different situations. Let's look at how to create functions, define input parameters, and work with functions in PowerShell scripts.

Creating a Function

At the most basic level, a function definition (i.e., the code that defines the function) requires the function keyword, the function's name, and a script block, as the following syntax shows:

function <name> \{ <script block> \}

The script block, which needs to be enclosed in braces, contains the statements that run when you call the function. You can include any PowerShell statement that you can run directly in the console. For example, the following code defines a function named FileSize1:

function FileSize1
\{
  dir C:\Windows |
  where \{$_.length -gt 100000\}
\}

Note that when you enter multiple lines of code at the command prompt, you should input a line and press Enter. You'll then see a >> prompt, which indicates that additional input is expected. After you've entered the entire function, press Enter twice to return to the normal command prompt (>).

As you can see, this function definition begins with the function keyword, followed by the function's name. The script block includes two commands in a single pipeline. The first command uses the Get-ChildItem cmdlet (represented by the dir alias) to retrieve the contents of the C:\Windows directory. The results are piped to the second command, which uses the Where-Object cmdlet (represented by the where alias) to filter out files so that only files larger than 100,000 bytes are included in the results.

When you create a function, PowerShell stores it in memory for the duration of your session. During that session, you can call the function at any time by simply entering the function's name, as in

FileSize1

When you press Enter, PowerShell runs the code in the script block and returns the results, as shown in Figure 1. These are the same results you would receive if you had run the script block commands directly in the PowerShell console.

As this example shows, creating a basic function is a straightforward process. Although the script block here contains only a simple set of commands, you can make the script block as complex as necessary, letting you easily repeat complex logic without re-entering the same commands over and over. However, in most cases, a function without input parameters limits how much you can do with that function, so let's take a look at how to use input parameters.

Adding Input Parameters

One way you can use input parameters in a function is to take advantage of the $args built-in variable. When you call a function in PowerShell, you can include parameter values with the function's name. If those values aren't associated with a named parameter, they're automatically saved to the $args array. You can then retrieve values from that array within your function.

For example, the following function uses $args:

function FileSize2
\{
  dir $args\[0\] |
  where \{$_.Length -gt 100000\}
\}

Notice that the first command in the script block references the first value in the $args array ($args\[0\]) rather than specifying a pathname (e.g., C:\Windows). As a result, when you call the FileSize2 function, PowerShell uses the first argument that you provide to identify the folder. If you provide more than one argument, PowerShell disregards the extra arguments because the function doesn't reference them.

To call the FileSize2 function, you simply enter the function name and pathname, making sure there's a space between them, such as

FileSize2 C:\Windows

When PowerShell receives this command, it calls the function, replaces $args\[0\] with C:\Windows, and returns the applicable contents from that folder, providing the same results as those shown in Figure 1. Note that if a pathname includes spaces, you should enclose it in quotes.

Figure 1: Creating and Running a Function

When you call a function, each argument that you include is added to the $args array. As a result, you can handle any number of arguments in your function. However, working with arguments in this way can get confusing as the numbers increase. This is especially problematic if you don't enter the arguments in the correct order when you call the function. In addition, there are limitations on how you can define the arguments. As a result, creating named parameters within the function definition is often a more effective way to handle arguments.

To create named parameters, you include the parameter names, which must be preceded by dollar signs, in parentheses after the function name. When you're creating more than one named parameter, you must use a comma to separate the parameter names. For example, the function definition

function FileSize3 ($dir, $minSize)
\{
  dir $dir |
  where \{$_.length -gt $minsize\}
\}

creates two named parameters: $dir and $minSize. The script block uses these parameters to identify the target folder and the minimum file size (in bytes), respectively.

When you call the FileSize3 function, you reference the parameter's name and value the same way you'd reference cmdlet options: You specify the parameter's name—which must be preceded with a hyphen (and not a dollar sign like you did when creating them)—followed by a space and the parameter's value. If you include more than one named parameter, you simply add another space followed by the additional parameter name/value pair, as in

FileSize3 -dir C:\Windows `
    -minSize 100000

Note that, in this case, I used the back tick (`) to continue the command to a second line.

When you call a function that includes named parameters, PowerShell runs the function and replaces the parameter placeholders in the script block with the parameter values in the calling statement. For example, PowerShell replaces $minSize with 100000. PowerShell then returns the result set generated by the script block, as shown in Figure 2.

Figure 2: Adding Named Parameters to a Function

If you specify the arguments in the same order as they're defined, you don't need to include the parameter names. For example, the command

FileSize3 C:\Windows 100000

returns the same results as the command in the previous example.

Specifying Default Values for Parameters

You might find that you want the code in your function's script block to use default values if no parameter values are provided when calling that function. The easiest way to achieve this is to define the default values in the function definition. For example, the following function definition provides default values for $dir and $minSize:

function FileSize4
  ($dir="C:\Windows\System32",
  $minSize=1000000)
\{
  dir $dir |
  where \{$_.Length -gt $minSize\}
\}

As you can see, all you need to do is add an equal sign followed by the default value to the parameter name. Now you can call the function without providing parameter values, as in

FileSize4

As Figure 3 shows, PowerShell automatically inserts the default values in place of the parameter placeholders in the script block.

Figure 3: Adding Default Values to Parameters

You can easily override the default parameter values when needed. For example, if you specify

FileSize4 C:\Windows 500000

the function returns data based on the two specified values, as Figure 4 shows.

Figure 4: Overriding Default Values

You can also provide some values and not others when calling a function. For example, the following command includes a value for the first parameter ($dir) but not the second parameter ($minSize):

FileSize4 C:\Windows

When the function runs, it'll use C:\Windows for $dir and the default value for $minSize. Thus, the result set will list files larger than 1,000,000 bytes in the C:\Windows directory.

When you specify a parameter value in a function call that's not in the same order as the parameters defined in the function definition, you must include the parameter's name. For example, the following command specifies only the $minSize parameter:

FileSize4 -minSize 500000

The function will use the default value for $dir and the 500000 value for $minSize, so the result set will list files larger than 500,000 bytes in the C:\Windows\System32 directory. If you were to provide only the $minSize value without the parameter name, PowerShell would assume that the value is meant for the $dir parameter because $dir is the first parameter defined in the function. For that reason, you must include the parameter name.

Specifying Parameter Types

In addition to assigning a default value to a parameter, you can strongly type the value by casting the variable. To do so, simply precede the parameter name with the data type name (or its alias) within brackets, as in

function FileSize5
  (\[string\] $dir="C:\Windows",
  \[int\] $minSize=1000000)
\{
  dir $dir |
  where \{$_.Length -gt $minSize\}
\}

Now $dir is defined with the String data type, and $minSize is defined with the Int32 data type. If you try to enter a value with the wrong type, you'll receive an error. For example, the following command attempts to use a string as an argument for $minSize, which is configured as an integer:

FileSize5 -minSize file

As Figure 5 shows, the command will generate an error because PowerShell cannot convert file to an Int32 value.

Figure 5: Strongly Typing Parameters in a Function

Working with Functions

Up to this point, the sample function calls have called the function directly, and the functions' results were returned to the console. However, functions are particularly useful when used in conjunction with other elements in PowerShell scripts. For example, you can use a function to assign a value or a collection to a variable. For example, the code

$files = FileSize5 C:\Windows 500000
foreach ($file in $files)
\{
  $file.Name + " is " +
    $file.Length + " bytes."
\}

uses the FileSize5 function to retrieve a list of files and assign that list to the $files variable. That variable is then used in a foreach loop to return each file's name and size, as shown in Figure 6.

Figure 6: Using a Function to Initiate a Variable

In addition to using functions to define variable values, you can use functions directly in a pipeline, along with other commands. For example, the following pipeline begins by calling the FileSize5 function:

FileSize5 C:\Windows 500000 |
foreach \{$_.name + " is " +
  $_.length + " bytes."\}

The function's results are then piped to the ForEach-Object cmdlet (referenced by the foreach alias), which generates information about each file returned by the function, as Figure 7 shows.

Figure 7: Using a Function in the Pipeline

Moving Forward

Functions are extremely useful when working with PowerShell scripts that perform the same tasks repeatedly. You can make your functions as simple or as complex as necessary. However, as I mentioned previously, the functions you create within a session are available only during that session. In the next lesson, I'll explain how to persist those functions so they're available whenever you need to call them.