Chapter Five:  
Functions
Functions
A function constitutes a list of statements with a user-assigned name. The function can be executed by typing its name. The statements included within the list will execute as if they had been typed on the console.
A function may be simple, such as :
>function Get-PowerShellProcess { Get-Process PowerShell }
A function may also be more complex. It may have the complexity of an application or a cmdlet. Functions, similar to cmdlets, may contain parameters as well. These parameters may be positional, named, dynamic, or switch.
Either a pipeline or console can read a function. Functions can be constructed to return values, which can be shown. These values can also be made part of variable assignments passed to cmdlets or other functions. A function can have a particular return value specified through the keyword return. This keyword will not suppress or affect other output designated to be returned from the function. However, using return will trigger an exit from the function on that line.
A function can have separate statement lists categorised by the keywords Process, Begin, and End. These three types of statement lists have distinct methods for handling pipeline input. A filter is a particular class of functions designated with the keyword Filter. Functions can also be constructed to behave or operate similar to cmdlets without requiring C# programming.
Function Syntax
The syntax for specifying a function is as follows:
function [<scope:>]<name> [([type]$parameter1[,[type]$parameter2])]
{
param([type]$parameter1 [,[type]$parameter2])
dynamicparam {<statement list>}
begin {<statement list>}
process {<statement list>}
end {<statement list>}
}
A function has the following components:
        List of PowerShell statements demarcated with brace symbols {}
        Function keyword
        Scope which is optional
        User selected name
        Named parameters which are optional
Simple Functions
A simple function is simply a standard function deployed without the optional components (named parameters and a scope modifier).
A simple function syntax is as follows:
function <function-name> {statements}
To illustrate, this function starts PowerShell in Administrator mode:
function Start-PSAdmin {Start-Process PowerShell -Verb RunAs}
The function can be used by invoking it with its name:
>Start-PSAdmin
Statements can be added to a function by typing different statements on separate lines, or by demarcation with the semicolon symbol (;).  At this stage, it would be informative to illustrate the concepts with a simple example.
Example: A function for finding .jpg files that were changed after a specific date
This function identifies all files with extension .jpg located in the path $env:UserProfile changed after the date specified by the $Start variable:
function Get-NewPix
{
$start = Get-Date -Month 1 -Day 1 -Year 2010
$allpix = Get-ChildItem -Path $env:UserProfile\*.jpg -Recurse
$allpix | Where-Object {$_.LastWriteTime -gt $Start}
}
Convenient functions can be organized into a toolbox and added into your profile.
Function Names
Functions may have any name assigned to them. The best practice recommendation, however, is for the names to conform to established standard PowerShell naming conventions for all commands. These conventions include a recommendation that the names comprise a pairing of a verb and a noun.  In doing so, the noun characterizes the item the function acts on, and the verb describes the function’s action. The verb should be one of the approved PowerShell standard verbs for commands. Standard verbs help keep the names of all commands coherent, straightforward, and obvious to users.
Functions Parameters
Named Parameters
A function can define named parameters of an arbitrary number. The named parameters have an assigned default value. Parameters can be defined inside or outside the function brace symbols {}. When defined within the brace symbols, a Param keyword must be used. The syntax is as follows:
function <name> {
param ([type]$parameter1[,[type]$parameter2])
<statement list>
}
When parameters are defined outside the brace symbols, then the required internal brace Param keyword may be omitted. The syntax is as follows:
function <name> [([type]$parameter1[,[type]$parameter2])] {
<statement list>
}
To illustrate, the external brace syntax may be used as follows:
>Function Add-Numbers($one, $two) {
$one + $two
}
The internal brace approach is the preferred method, but either approach will give the desired result. When the function is executed, the supplied parameter value is assigned to each variable that contains the name of the parameter. The variable value may be used inside the function.
Let us consider a simple example to illustrate these concepts.
Example: Get-SmallFiles function
In this illustration, a function named Get-SmallFiles is defined. The function includes a parameter called $Size. The function shows all files smaller than a user than the $Size parameter value, and does not include directories:
function Get-SmallFiles {
Param($Size)
Get-ChildItem $HOME | Where-Object {
$_.Length -lt $Size -and !$_.PSIsContainer
}
}
Inside the function, the variable called $Size, which matches the defined parameter name, can be used. The function can be used with this command
>Get-SmallFiles -Size 50
A value can be passed to the named parameter without referring to its name. To illustrate, this command produces identical results to the command above:
> Get-SmallFiles 50
A parameter can have an assigned default value. The default value can be defined using a definition expression. The definition expression involves placing an equal sign = to the right of the parameter followed by the default value. This is illustrated in the following revised Get-SmallFiles function definition:
function Get-SmallFiles ($Size = 100) {
Get-ChildItem $HOME | Where-Object {
$_.Length -lt $Size -and !$_.PSIsContainer
}
}
If Get-SmallFiles is typed with the value omitted, the function will assign a 100 value to $Size. If, on the other hand, a value is supplied, the function will be evaluated with the supplied value. The other option is to attach a help string describing the parameter default value. This is done by first attaching a PSDefaultValue attribute to the parameter description. The second step is to specify the PSDefaultValue Help property of the attached attribute. This example shows how to provide a brief help string describing the specified default value for the Size parameter of the function Get-SmallFiles,by attaching a PSDefaultValue attribute:
function Get-SmallFiles {
param (
[PSDefaultValue(Help = '100')]
$size = 100
)
}
Positional Parameters
A function parameter that does not have a name assigned to it is called a positional parameter.
PowerShell assigns values to positional parameters by using the order of the supplied function’s parameter values. The values for the positional parameters are assigned to a variable called $args, which is an array type, and ordered to match with the function’s parameter values. To illustrate, the first value supplied after the name of the function is assigned a value on the first of the positions in $args, $args[0].
The Get-Extension function in this illustration attaches a file name .txt extension to a supplied file name positional parameter:
>function Get-Extension {
$name = $args[0] + ".txt"
$name
}
The output that is obtained when the function is invoked in the command line is as follows:
>function Get-Extension {
$name = $args[0] + ".txt"
$name
}
>Get-Extension myTextFile
is:
myTextFile.txt
Switch Parameters
A function parameter that has a name but not a required value is called a switch parameter. The parameter is supplied to the function by using only its name. The switch parameter is defined by specifying its type as [switch] before its name in the function definition, as shown in the following illustration:
>function Switch-Item {
param ([switch]$on)
if ($on) { "Switch on" }
else { "Switch off" }
}
When the switch parameter name occurs after the name of the function, the function will show a "Switch on" signal. If the name of the switch parameter is not supplied, however, then the function will show a "Switch off" signal. These concepts are illustrated in the following command sequence:
>function Switch-Item {
param ([switch]$on)
if ($on) { "Switch on" }
else { "Switch off" }
}
>Switch-Item -on
Switch on
>Switch-Item
Switch off
The switch parameter can also be supplied to the function using Boolean value notation. This is illustrated in the following command sequence:
>Switch-Item -on:$true
Switch on
>Switch-Item -on:$false
Switch off
Functions and Pipeline Objects
Any function has the ability to take a pipeline input. In this input, the Process, Begin, and End keywords control how the function handles the processing of the pipeline. The following syntax illustrates how these three keywords are used:
function <name> {
begin {<statement list>}
process {<statement list>}
end {<statement list>}
}
The statement list following the Begin keyword runs only once at the start of the function evaluation. It is important to note that when the Process, Begin, and End keyword blocks are used, all function code has to be contained within those blocks. As long as one of these blocks is defined, any code that resides outside of the blocks will not be recognized or executed.
The statement list bound to the Process keyword runs once for each pipeline input object. While this block is executing, each of the objects of the pipeline will be allocated, one object at a time, to the variable $_, which is an automatic variable. When all the pipeline objects have been received by the function, then the statement list with the keyword End runs once.
If no Process, Begin, or End keywords are found in the function definition, then PowerShell treats all function statements collectively as that of an End block statement list.
The following function uses only the Process keyword. The function shows output from a sample pipeline:
>function Get-Pipeline
{
process {"The value is: $_"}
}
This properties of this function can be demonstrated using the following command, which enters a comma-separated list of numbers as the pipeline input:
>1,2,4 | Get-Pipeline
The value is: 1
The value is: 2
The value is: 4
When a function is used within a pipeline, the pipeline input objects of the function are allocated to the variable $input, which is an automatic variable. The function will run all statements within the Begin block before any of the pipeline objects are sent to the function. The function will run all statements within the End block after all pipeline input objects have been received.
The following example illustrates the properties of the automatic $input variable for a function using a Begin keyword and an End keyword. The function Get-PipelineBeginEnd is defined as follows:
>function Get-PipelineBeginEnd
{
begin {"Begin: The input is $input"}
end {"End:   The input is $input" }
}
This command and its resulting output illustrates how the function processes a pipeline input:
>1,2,4 | Get-PipelineBeginEnd
Begin: The input is
End:   The input is 1 2 4
In the case that the Process keyword is additionally used in the function definition, then each pipeline input object is removed from the $input variable and allocated to $_. The following function has a Process keyword in its definition:
function Get-PipelineInput
{
process {"Processing:  $_ " }
end {"End:   The input is: $input" }
}
In this illustration, each function pipeline input object is sent for processing by the Process keyword statement block after it is piped. The Process keyword statements will run a single object at a time. The automatic $input variable will be empty when the evaluation of the function arrives on the End block evaluation. This is demonstrated by the following output:
>1,2,4 | Get-PipelineInput
Processing:  1
Processing:  2
Processing:  4
End:   The input is:
Filters
A function type that is specifically designed to run each pipeline object is called a filter. A filter is similar to a function that has only a Process{<statement list>} block. The following shows the filter syntax:
filter [<scope:>]<name> {<statement list>}
The example filter below collects log entries from a running pipeline and then shows only either the entry message portion or the whole entry:
filter Get-ErrorLog ([switch]$message)
{
if ($message) { Out-Host -InputObject $_.Message }
else { $_ }
}
Function Scope
A function only exists within the scope which it is created. If a script creates a function, then all statements within the script can access the function. A function created by a script cannot be accessed from within the console by default. The function scope can additionally be specified. To illustrate, the function below shows had to add a function to a global scope:
function global:Get-DependentSvs {
Get-Service | Where-Object {$_.DependentServices}
}
A function that has a global scope can be used at the console, in other functions, and in scripts. In general, each function creates a function scope. The items created within the function, such as variables, exist only within that function’s scope.
A function variable cannot, however, be called outside the function scope even if the function itself is within the global scope. This scenario is illustrated by the following command sequence and output:
function global:Send-Greeting {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string] $Name
)
Process
{
Write-Host ("Hello " + $Name + "!")
}
}
>Send-Greeting –Name user
Hello user!
>$Name
>
Function: Drive
All PowerShell filters and functions are stored automatically within the drive called Function:. The Function provider in PowerShell exposes this drive. The way to refer to this drive is to type a colon symbol (:) after the word Function, similar to a file system drive. This command shows all current session functions:
>Get-ChildItem function:
More information about the Function: drive is available from the function provider help topic accessed by typing Get-Help Function. The function statement list is specified in the function definition according to the function syntax. To illustrate, to show the commands of the PowerShell built-in Help function, enter the following command:
>(Get-ChildItem function:help).Definition
An alternative syntax is shown below:
>$function:help
Reusing Functions
Functions created in a session are only available for use in that particular session. Once the session is closed, the function is no longer available and calling the function in a new session will return an error. However, a function can be made universally available in any current or future session by adding the function to your profile or saving it to a script file.
Consider below the following function called Get-CmdletAlias, which obtains the alias of every cmdlet:
function Get-CmdletAlias ($cmdletname) {
Get-Alias |
Where-Object -FilterScript {$_.Definition -like "$cmdletname"} |
Format-Table -Property Definition, Name -AutoSize
}
One useful PowerShell profile is the “all users for all hosts” profile accessed by either locating the $PSHOME\Profile.ps1 file or entering the following script, $env:windir\System32\PowerShell\v1.0\Profile.ps1, in PowerShell. To save a function for future use, next enter the function in the script file. In doing so, the function can be invoked in all PowerShell session sessions. This scenario is demonstrated as follows, using the Get-Command cmdlet example from above:
>Get-CmdletAlias Get-Command
Definition  Name
----------  ----
Get-Command gcm
The function may also be saved in a script file, such as AliasFunction.ps1, located in the folder <path>. Then, invoking the following command will bring the function into the current session as needed:
<path>\AliasFunction.ps1
Function Help
The help file for cmdlets, scripts, providers, and functions can be displayed by calling the cmdlet Get-Help. The Get-Help cmdlet invoked with the name of the function supplied for the Name parameter gets help for the specified function. To illustrate, to show the help file for the function Get-MyDisks using the Get-Help cmdlet, enter this command:
>Get-Help Get-MyDisks
Help for a function can be written by making use of either of the following methods:
    Comment-Based function help: Use comment-based special keywords to create a topic in the function help file. The help comments may be placed in one of four locations. These are the lines before the keyword function, outside the function braces, after the right brace of the statement list, or outside the function braces before the left brace of the statement list. We will discuss the syntax in further detail in a later section.
    XML-Based function help: This type of help is similar to that of cmdlets. This type of help is required in help-topic localization for multiple languages and is created using the .ExternalHelp version of the comment-based help special keyword within the comments.
Comment-Based Help Syntax
Comment-based function help, which has an identical format to that produced using XML files, is viewed by invoking the Get-Help cmdlet and using any of its parameters.
The general comment-based help syntax is as follows:
<#
.<help keyword>
<help content>
#>
or:
.<help keyword>
<help content>
Comment-based help may take the form of a single-line comment or  a sequence of comments. To add a multi-line comment, enclose the comment block within <# and #>. Alternatively, precede each comment line with the comment symbol (#). In such an arrangement, PowerShell will interpret all #’d block lines as comments.
Help topic comment-based lines must be neighboring. In other words, there must be one or more empty lines separating the final comment line of the non-help comment topic and the first line of the comment-based help topic.
Comment-based help sections are defined using keywords. A dot symbol (.)  must precede a keyword within the comment-based help. The order of the keywords may be arbitrary, and the names of the keywords are not case-sensitive. To illustrate, a function description is preceded by the keyword "Description" as follows:
<#
.Description
Get-Function displays the name and syntax of all functions in the session.
#>
One or more keywords are required in a comment block. A comment block may have the same keyword appearing multiple times, such as "EXAMPLE". The keyword-designated help content may range many lines and starts on the subsequent line to the keyword.
The function comment-based help may be placed in a single location from a choice of the following three:
       Preceding the keyword used for functions. Only a single line that is blank is permitted between the keyword for the function and the final function help line.
        When the body of the function concludes
        When the body of the function starts
To illustrate:
<#
.<help keyword>
<help content>
#>
function Get-Function { }
or:
function Get-Function
{
# function logic
<#
.<help keyword>
<help content>
#>
}
or:
function Get-Function
{
<#
.<help keyword>
<help content>
#>
# function logic
}
are all appropriate templates for creating a comment-based function help topic.
Exercises
5.1. How does PowerShell run function commands?
5.2. Can functions have parameters? If so, what types?
5.3. Where are the two places where function parameters can be read?
5.4. What are the components of a function?
5.5. What types of functions can accept input from a pipeline?
5.6. What is the scoping rule for functions?
5.7. What does the Function: drive do?
Chapter Summary
The key points of this chapter were:
        A function is a list of statements with a user assigned name.
        Functions should have names that follow PowerShell naming conventions.
        Parameters may be used with functions.
       Filters are a type of function that runs on each of the objects in a pipeline.
        Functions can be enhanced through the creation comment-based or XML-based help.
In the next chapter you will learn about modules and providers.