PowerShell Basics: Writing Functions

Defining a Function
This is the basic template that should be used for any functions.

function Verb-Noun {
   [CmdletBinding()]
   param(
      [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
      [string]$Something
   )
   BEGIN{}
   PROCESS{}
   END{}
}

 

Process Order
The BEGIN and END blocks only run once. The PROCESS block will act differently depending on how you call the function.

#Will execute the PROCESS block only once for $Input.
#Therefore if $Input is an array you will need a foreach loop to handle each object.
Verb-Noun -Input $Input

#Will execute the PROCESS block once for each element of $Input as it is piped into the function one by one.
$Input | Verb-Noun

 

Cmdlet Binding
Using the [CmdletBinding()] tag allows the use of -Verbose but you can also set more advanced features such as the SupportsShouldProcess

function Verb-Noun{
   [CmdletBinding()]
   param()
}

 

Defining Parameters
The following are the different options you can set when defining a paramter. Note that Options of the same type can be added to the same line within the brackets separated by a “,”

function verb-noun{
   param(
      [parameter(Mandatory=$true)]
      [parameter(Position="1")]
      [parameter(ValueFromPipeline=$true)]
      [parameter(ValueFromPipelineByPropertyName=$true)]
      [parameter(HelpMessage="String")]
      [parameter(ParameterSetName = '')]
      [Alias(Name1,Name2)]
      [ValidateCount(Min,Max)]
      [ValidateLength(Min,Max)]
      [ValidatePattern(regexString)]
      [ValidateRange(Min,Max)]
      [ValidateSet("Steve","Mary")]
      [ValidateScript({Script Block to $True/$False})]
      [String / Int / Array]$ParamName
   )
}

 

Parameter Set Name
You can define differences in your accepted parameters and give them set name. Powershell will then allow the paramameters to be entered in different ways, eg. pipeline vs. long params. This forces the parameters to be fed into your function how you wish.

function Verb-Noun {
   [CmdletBinding(DefaultParameterSetName = 'Going')]
   param(
      [parameter(Mandatory=$true)]
      $Name,

      [parameter(ParameterSetName='Going')]
      [switch]$Go,

      [parameter(ParameterSetName='Stopping')]
      [switch]$Stop
   )

   if($Go){
      Write-Host "Go"
   }
   elseif($Stop){
      Write-Host "Stop"
   }
   else{
      Write-Host "?"
   }

   Write-Host "$($PSCmdlet.ParameterSetName)"
}

 

Dynamic Paramters

Dynamic parameters can greatly help end users in using your custom functions. Below is a quick example of the syntax used, for a worked example on how to implement dynamic parameters see my Github


Function Verb-Noun {
   Param ()
   DynamicParam {
      #Define all Dynamic Parameters in this block
      $DynamicParams = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
      Return $DynamicParams
   }
   PROCESS {

   }
}

Output
There are a few ways of writing output. The most common is for when writing a function that returns multiple objects as output.

New-Object -TypeName PSObject -Property @{
   'Label 1' = $param
   'Label 2' = $Param.property
   'Label 3' = Some Calculation
} | Add-Member -TypeName 'Something.Something' -PassThru

#Or you can use the Type Accelerator

[PSCustomObject]@{
   StartType = $SvcStartType
   Something = 2048/1GB
} | Add-Member -TypeName 'Something.Something' -PassThru

 

Output Streams
You can also write to the console using different streams. This is good to avoid writing multiple types of output from a function as this is best practise. In many cases using Write-Host is wrong unless you want to create a user experience.

Write-Verbose "Use this to write more information"

#If you wanted to redirect the verbose (Stream 4) output to a file user:
Test-Script -Verbose 4>&1  | Out-File o.txt

Write-Warning "Error Messages that Stand Out"

Write-Host "Use this to write in different colours" -foregroundcolor "Red"

 

Help Text
Whilst tedious it is important any tools you make with the intention or reusing them should have ample help text to accompany


<# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ComputerName Description of parameter .EXAMPLE Example of how to use this cmdlet .EXAMPLE Another example of how to use this cmdlet #>
function Verb-Noun {
   # Some function
}

 

Support Should Process

Below is an example of using support for ShouldProcess. The default impact level for the shell to ask the user to confirm is “High” so by setting this as the ConfirmImpact level we are telling the cmdlet to confirm each time ShouldProcess is called. You need to provide a string as an argument. This will be the description of what is about to be done. Using the -WhatIf switch on this function would trigger all ShouldProcess calls but not run them.

function Verb-Noun{
   [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact="High")]
   Param ()

   Write-Host "Performing some basic task"

   If ($PSCmdlet.ShouldProcess('About to make a system change')){
      Write-Host "Performing some high impact task"
   }
}

Leave a Reply

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