← PowerShell course
7

Functions, Parameters & Safe Tools

25 min

Stop retyping the same one-liners. Package your logic into reusable, well-behaved functions with typed parameters, mandatory inputs, object output, and built-in -WhatIf safety.

By the end you can
  • Define a function using the Verb-Noun naming convention and understand why approved verbs matter
  • Declare typed parameters with param() including default values and [Parameter(Mandatory)] constraints
  • Emit objects from a function instead of Write-Host so output is pipeline-friendly
  • Promote a function to an advanced function with [CmdletBinding()]
  • Add SupportsShouldProcess so callers get -WhatIf and -Confirm for free

Turning One-Liners Into Tools

A function is a named, reusable block of logic. Once defined, it behaves exactly like any built-in cmdlet — it accepts parameters, works in a pipeline, and returns objects.

Verb-Noun naming

PowerShell enforces a Verb-Noun convention (e.g. Get-DiskReport, Restart-StaleService). The verb should come from the approved list:

Get-Verb          # shows all approved verbs

The basic skeleton

function Get-Greeting {
  'Hello, world!'
}
Get-Greeting

Any expression not captured by a variable is automatically emitted to the pipeline — no return keyword required.

Adding parameters with param()

function Get-Greeting {
  param(
    [string]$Name = 'World'
  )
  "Hello, $Name!"
}
Get-Greeting -Name 'Alice'
  • Type constraint [string] coerces or rejects incompatible input.
  • Default value = 'World' makes the parameter optional.

Mandatory parameters

function Get-Greeting {
  param(
    [Parameter(Mandatory)]
    [string]$Name
  )
  "Hello, $Name!"
}

Omitting -Name now prompts the caller rather than silently using $null.

Returning objects, not text

Avoid Write-Host inside reusable functions — it writes to the screen only and breaks pipelines. Emit a [pscustomobject]:

function Get-DiskReport {
  param([string]$ComputerName = $env:COMPUTERNAME)
  $disk = Get-PSDrive C
  [pscustomobject]@{
    ComputerName = $ComputerName
    UsedGB       = [math]::Round(($disk.Used / 1GB), 2)
    FreeGB       = [math]::Round(($disk.Free / 1GB), 2)
  }
}
Get-DiskReport | Export-Csv disks.csv -NoTypeInformation

Advanced functions and SupportsShouldProcess

Adding [CmdletBinding()] unlocks the common parameters (-Verbose, -ErrorAction). For any function that changes state, add SupportsShouldProcess and wrap the destructive call in $PSCmdlet.ShouldProcess(...). Callers then get -WhatIf and -Confirm for free:

function Restart-StaleService {
  [CmdletBinding(SupportsShouldProcess)]
  param(
    [Parameter(Mandatory)]
    [string]$ServiceName
  )
  if ($PSCmdlet.ShouldProcess($ServiceName, 'Restart service')) {
    Restart-Service -Name $ServiceName
  }
}
Restart-StaleService -ServiceName Spooler -WhatIf
# What if: Performing the operation "Restart service" on target "Spooler".

This pattern is the difference between a script run nervously once and a tool the whole team trusts.