Functions in PowerShell allow you to combine multiple statements and improve the reusability of your code. In this post, you will learn how to scope functions, define parameters, assign data types, and return values.
Avatar

If you have worked with VBScript before, the functions in PowerShell might appear familiar. However, it is important to note that major differences exist between Microsoft’s scripting languages.

Whether the function only contains one statement or a complex sequence of commands, you can execute its containing code by calling the function’s name together with the required parameters. This avoids redundant script blocks and facilitates code maintenance.

The use of functions is not required

In contrast to most compiled languages, such as C, the use of functions is not required in PowerShell. Thus, your script can contain large parts of code that isn’t encapsulated in any function.

It is worth pointing out that, even though PowerShell is an object-oriented language, functions are defined as in procedural languages and not as methods in classes.

Functions as scope of variables

In PowerShell, as in other programming languages, functions define the scope of variables. The values of variables defined within a function block are not available outside the function. However, to avoid undesirable side effects, you should not use the same name for local and global variables.

Scopes also affect the functions themselves. By default, functions that you define in a script are not available at the PowerShell prompt. You can change this by using the scope identifier, as in the example below:

function global:Get-UserInput

With this command, you are extending the scope of the function Get-UserInput to global, which makes the function available outside the script where you defined it.

Loading functions in the profile

If you define a function at the PowerShell prompt to save typing of complex commands, the function only exists during this session. To make it available in future sessions, you have to add it to your PowerShell profile.

In an interactive session, you will probably only use simple functions with just one statement; however, functions can get quite complex in scripts.

The syntax of a function

PowerShell help describe the general form of functions 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>}

}

The definition begins with the keyword function; a declaration of the return value is not provided. As mentioned above, you can prepend the name of the function with a value for the scope. The naming should follow the PowerShell convention in the form verb-noun, as with all integrated PowerShell cmdlets (Get-Process, for instance).

Defining parameters

An essential feature of functions is that their statements don’t just have to execute code with constant values; you can also pass changing values as arguments. PowerShell offers many more features here than other languages do, but this also means a steeper learning curve. It is already unusual that two different ways exist to define parameters.

As in most languages, you can define the list of parameters directly after the function name. Alternatively, you can define the parameters at the beginning of the function block with the keyword param.

It is a matter of taste which option you prefer. However, if you intend to use several of the numerous attributes and work with predefined values, you should use the param block to improve the readability of your script.

Named parameters

Microsoft’s cmdlets mainly use named parameters. Hence, you should follow this convention for your functions. In the declaration, you define the name of a parameter as a variable, which allows you to access its value in the function.

function Start-App($AppName){

    $AppID = Get-StartApps | where Name -like $AppName
    Start-Process "explorer.exe" -ArgumentList ("shell:AppsFolder\" + $AppID.AppID)

}

This example packs the command to run a Windows 8.x app in a function, so that you only have to pass the name of the app (or a part of it) to start it. For instance, if you want to launch the Notepad app, you could call the function in the following way:

Start-App -AppName "notepad"

Assigning types and values to parameters

In the above example, the sole parameter is defined without the use of additional attributes. However, by assigning a data type, you could ensure that the function accepts only a value of the type String.

function Start-App([String] $AppName){

	<statements>

}

In most cases, you will want to intercept the function call if no parameter has been passed. You have two options here: You either predefine the value of an argument or you require the use of a particular parameter. You can set a default value in the declaration, like this:

function Start-App([String] $AppName = "Editor"){

	<statements>

}

If the function Start-App is called without AppName, Notepad is automatically started. If you want to prevent the function from being called without the parameter AppName, you can use the Mandatory attribute, like this:

function Start-App{

	Param(
	[parameter(Mandatory=$true)]
	[String]
	$AppName 
	)

	<statements>

}

This example uses the syntax that defines the parameter with the help of Param within the function. It determines that a value for AppName has to be passed; otherwise, the user will be prompted to enter its value. The function also expects a value of type String.

Validating parameter values

In addition to the Mandatory attribute, PowerShell offers a variety of attributes to validate the passed parameters. These include the following:

  • AllowNull
  • AllowEmptyString
  • ValidateCount (specifies the minimum and maximum number of parameter values)
  • ValidateLength (specifies the minimum and maximum number of characters in a parameter)
  • ValidatePattern (specifies a regular expression that is compared to the parameter)

You can find a complete list of the validation options in the PowerShell help under about_Functions_Advanced_Parameters.

Positioning parameters

Named parameters make it easier to call a function if you use meaningful names. This is also helped by the fact that the order of the arguments doesn’t matter. However, if you want to work without parameter names, you have to pass them in the exact order that you declared them. Alternatively, you can enforce the position of an argument in the definition of the function.

MyFunc{

	Param(

		[parameter(position=1)]
		$Address,
		[parameter(position=0)]
		$ComputerName

		)

	<statements>

}

In this example, the parameter ComputerName always has to be passed at the first position if you call it without an identifier. For instance:

MyFunc "My PC" "192.168.10.11"

Reading parameter values from $args

The easiest use of positional parameters is to read the parameter values from the array $args. The following example calls Test-Connection first with the host name and then with the IP address:

function MyPing{

	$CompName = $args[0]
	$IP = $args[1]

	Test-Connection $CompName
	Test-Connection $IP

}

In this case, no validation is taking place. The function MyPing expects the computer name as the first argument ($args[0]) and the IP address as the second argument ($args[1]).

Piping data to functions

You don’t have to pass static values to a function via parameters. PowerShell functions also accept input through pipes. Typically, you want to pass the output of a cmdlet or the contents of a file to a function. In the simplest case, you go without the declaration of parameters and read the values from the pipeline by iterating over all objects of the predefined variable $input:

function Start-App([String] $AppName){

    foreach($App in $input){
     if($App.Name -like $AppName){
        Start-Process "explorer.exe" -ArgumentList ("shell:AppsFolder\" + $App.AppID)
        }

    }

}

The following example is a variation of Start-App, defined above, except that Get-StartApps (gets the names and AppIDs of apps on the Start screen) isn’t called in the function. Instead, we pipe the output of Get-StartApps into our function:

Get-StartApps | Start-App "Paint*"

As of PowerShell 3.0, additional options exist to process the input of a pipe. This includes custom attributes in the declaration and the partition of the function in the begin, process, and end blocks.

Returning values

If you have experience with other programming languages, you know that a function returns a value to the calling subroutine. JavaScript and PHP have the return keyword for this purpose; in VBScript, you use a variable with the same name as the one of the function.

PowerShell also knows the return keyword; however, it follows a different logic. In general, the purpose of return is to end the execution of a code section and to give the control back to the parent block.

If you add a parameter to the return statement, the value will indeed be returned to the calling subroutine. However, this also applies for all other statements with an output. This means that any output produced in the function will be stored in the variable together with the return parameter.

Subscribe to 4sysops newsletter!

function rTest{

	$a = 5
	$b = "This is a test."
	$a
	return $b

}

If you call the function rTest with the command $r = rTest, the values of $a and $b would be stored in the array as separate elements. Thus, you don’t have to use return to return values from a PowerShell function. In the above example, the result would be the same if you place the variable $b in the line above return and end the function with an empty return.

9 Comments
  1. Avatar
    Adam 7 years ago

    Loved discovering about advanced function parameters, thanks for that.

  2. Avatar
    Bilal 7 years ago

    When I define parameter inside a function, this does not work with tab completion. Is there anything wrong in this example code;

    function Get-DJOSInfo {
    [cmdletBinding(SupportsShouldProcess=$True,ConfirmImpact=’Low’)]
    param (
    [Parameter(Mandatory=$True,
    ValueFromPipeline=$True,
    ValueFromPipelineByPropertyName=$True)]
    [Alias(‘hostname’)]
    [ValidateLength(5,20)]
    [ValidateCount(1,10)]
    [string[]]$computerName,

    [switch]$nameLog
    )

  3. Avatar
    Cem (Rank 1) 6 years ago

    Well explained. Thank you!

  4. Avatar
    Nashev 6 years ago

    What about calling conventions?

    Could I use brackets around passing arguments when I call a function and commas between them? Or just like in the command line, I must pass arguments divided by spaces?

    What about methods of objects, added by Add-Member -memberType ScriptMethod ? Why I can’t call this methods without brackets?

  5. Avatar

    Nashev..

    As long as your parameter is configured to accept multiple inputs (i.e. define a [string] as [string[]]), you can input an array or comma delimited list. (I’d guess any collection would probably work just fine).

    I don’t know the answer about adding a method :-\

    But, the answer to Bilal’s question is simple, and I don’t see an answering post.. so if anyone cares or is interested:
    Use a [ValidateSet()] definition in the parameter.. each item in the set will prepopulate by hitting the tab key. Example:

    [parameter(Mandatory=$true)]
    [ValidateSet(‘Value1′,’Value2′,’Value3’)]
    [string]$ValueParam

    So, at the command line if you had -ValueParam and hit tab, it will cycle through the options.  Other than that, it could be done with a dynamic parameter (I believe).. but that’s beyond me for now 🙂

    David F.

  6. Avatar
    Nashev 6 years ago

    While waiting for Your kind answer I’ve noticed in stackoverflow about page https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_methods where MS describes a method’s call notation:

    To perform or “invoke” a method of an object, type a dot (.), the method name, and a set of parentheses “()”. If the method has arguments, place the argument values inside the parentheses. The parentheses are required for every method call, even when there are no arguments.

  7. Avatar
    Chantal 5 years ago

    I try to create function  to manipulate status of App Pool remotly

    i have server and appPoolName in variable  but when invoke  … $appPoolName note working

    Invoke-Command -ComputerName “$serverName” { import-module WebAdministration; Get-WebAppPoolState -Name $appPoolName -ErrorAction SilentlyContinue }

    how can i subtitute the value for the $appPooName variable ?

    thank’s in advance

     

    • Avatar
      Ravi Kumar 3 years ago

      The  Following will work and I have tested

      Invoke-Command -ComputerName  $serverName  -ScriptBlock {Get-WebAppPoolState |foreach-object{$_.Value}}

  8. Avatar
    Ali 2 years ago

    Thanks very useful

Leave a reply

Please enclose code in pre tags: <pre></pre>

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account