How to Write Reusable PowerShell Functions
PowerShell—love it or hate it, if you work in automation, DevOps, or systems administration, you’re going to write PowerShell scripts. And if you’re doing it properly, you’ll realize that your scripts keep evolving into something bigger, something that needs to be modular, maintainable, and—yes—reusable.
The Case for Reusability
Here’s the thing: writing scripts is easy. Writing scripts that don’t make you regret your life choices six months later? That’s an art. And the cornerstone of that art is reusability.
Reusable PowerShell functions:
- Reduce duplication – Write once, use everywhere.
- Improve maintainability – Fix bugs in one place rather than hunting them across dozens of scripts.
- Enhance readability – Self-contained functions make scripts easier to understand.
- Boost performance – Well-structured functions can be optimized independently.
- Facilitate testing – Modular functions are easier to validate with unit tests.
The Anatomy of a Well-Written PowerShell Function
A great PowerShell function has a few key characteristics:
- A clear purpose – It should do one thing and do it well.
- Parameterization – Accept input rather than relying on hardcoded values.
- Proper output handling – Returns objects, not just strings.
- Error handling – Graceful failure rather than catastrophic meltdown.
- Documentation – So future-you (and your colleagues) know what it does.
Step 1: Naming Your Function
PowerShell follows a verb-noun naming convention. Use Get-
, Set-
, New-
, Test-
, Invoke-
, etc. Microsoft provides a list of approved verbs (Get-Verb), and sticking to them ensures consistency.
Example:
function Get-UserInfo {
param (
[string]$Username
)
# Function logic here
}
Step 2: Using Parameters Properly
Parameters make your function flexible and reusable. Use [Parameter()]
attributes for validation and [ValidateSet()]
to enforce allowed values.
Example:
function Get-UserInfo {
param (
[Parameter(Mandatory = $true)]
[string]$Username
)
Get-ADUser -Identity $Username
}
Step 3: Returning Objects, Not Just Text
A well-structured function returns objects, not formatted text. This allows users to filter, sort, and manipulate data.
Bad Example:
function Get-UserInfo {
param ([string]$Username)
$user = Get-ADUser -Identity $Username
"User: $($user.Name) - Email: $($user.EmailAddress)"
}
Good Example:
function Get-UserInfo {
param ([string]$Username)
Get-ADUser -Identity $Username | Select-Object Name, EmailAddress
}
Step 4: Handling Errors Gracefully
Use Try/Catch
to prevent ugly red error messages from ruining your day. Write errors to $Error
and log them properly.
Example:
function Get-UserInfo {
param ([string]$Username)
try {
Get-ADUser -Identity $Username -ErrorAction Stop
}
catch {
Write-Error "User not found: $Username"
}
}
Step 5: Adding Documentation
PowerShell supports comment-based help. Use it!
<#
.SYNOPSIS
Retrieves Active Directory user information.
.DESCRIPTION
This function fetches user details from AD based on the provided username.
.PARAMETER Username
The username of the user whose details should be retrieved.
.EXAMPLE
Get-UserInfo -Username "jdoe"
#>
Step 6: Packaging Functions into Modules
Reusable functions belong in modules, not scattered across different scripts. Save your functions in a .psm1
file and import them using Import-Module
.
Example:
- Save your function inside it.
Import it in your scripts:
Import-Module MyPowerShellModule
Get-UserInfo -Username "jdoe"
Create a module file:
MyPowerShellModule.psm1
Final Thoughts
PowerShell isn’t just about quick and dirty scripting; it’s a serious automation tool. Writing reusable functions saves time, reduces frustration, and makes your scripts infinitely more powerful.
So the next time you’re about to copy-paste a chunk of PowerShell code for the third time—stop. Take a deep breath, turn it into a function, and thank yourself later.