PowerShell Functions
A function is a named, reusable block of code. Instead of writing the same logic multiple times throughout a script, a function packages that logic under a name — and that name can be called whenever the logic is needed. Functions make scripts shorter, easier to read, and simpler to maintain.
Why Use Functions?
Without Functions With Functions
---------------------- ----------------------
# Script repeats code function Get-DiskStatus {
$drive = Get-PSDrive C $drive = Get-PSDrive C
$freeGB = $drive.Free / 1GB $drive.Free / 1GB
Write-Host "Free: $freeGB" }
# Repeated 10 times in script # Called once, used 10 times
... Get-DiskStatus
Basic Function Syntax
function FunctionName {
# Code block
}
Simple Function
function Say-Hello {
Write-Host "Hello from PowerShell!"
}
# Call the function
Say-Hello
Output:
Hello from PowerShell!
Function with Parameters
Parameters let functions accept input values. This makes functions flexible and reusable.
function Greet-User {
param (
$Name
)
Write-Host "Hello, $Name! Welcome to eStudy247."
}
# Call with argument
Greet-User -Name "Ananya"
Greet-User -Name "Kiran"
Output:
Hello, Ananya! Welcome to eStudy247.
Hello, Kiran! Welcome to eStudy247.
Function with Multiple Parameters
function Add-Numbers {
param (
$Number1,
$Number2
)
$sum = $Number1 + $Number2
Write-Host "$Number1 + $Number2 = $sum"
}
Add-Numbers -Number1 15 -Number2 25
Add-Numbers -Number1 100 -Number2 300
Output:
15 + 25 = 40
100 + 300 = 400
Function with Default Parameter Values
function Send-Greeting {
param (
$Name = "Guest",
$Message = "Welcome!"
)
Write-Host "$Message, $Name"
}
# With arguments
Send-Greeting -Name "Priya" -Message "Good morning"
# Without arguments – uses defaults
Send-Greeting
Output:
Good morning, Priya
Welcome!, Guest
Returning Values from a Function
A function returns a value using the return keyword (or by simply producing output in the last statement).
function Get-SquareRoot {
param ($Number)
$result = [math]::Sqrt($Number)
return $result
}
$root = Get-SquareRoot -Number 144
Write-Host "Square root of 144 is: $root"
Output:
Square root of 144 is: 12
Implicit Return (No return Keyword)
function Get-FullName {
param ($FirstName, $LastName)
"$FirstName $LastName" # This line's output becomes the return value
}
$name = Get-FullName -FirstName "Arjun" -LastName "Sharma"
Write-Host "Full name: $name"
Output:
Full name: Arjun Sharma
Returning Multiple Values
function Get-Stats {
param ($Numbers)
$min = ($Numbers | Measure-Object -Minimum).Minimum
$max = ($Numbers | Measure-Object -Maximum).Maximum
$avg = ($Numbers | Measure-Object -Average).Average
return @{
Min = $min
Max = $max
Avg = [math]::Round($avg, 2)
}
}
$data = @(10, 45, 23, 88, 56, 72)
$result = Get-Stats -Numbers $data
Write-Host "Min: $($result.Min)"
Write-Host "Max: $($result.Max)"
Write-Host "Avg: $($result.Avg)"
Output:
Min: 10
Max: 88
Avg: 49
Advanced Function with [CmdletBinding]
Adding [CmdletBinding()] to a function makes it behave like a proper PowerShell cmdlet. It unlocks built-in parameters like -Verbose, -Debug, and -WhatIf.
function Remove-TempFiles {
[CmdletBinding(SupportsShouldProcess=$true)]
param (
[string]$FolderPath
)
$files = Get-ChildItem -Path $FolderPath -Filter "*.tmp"
foreach ($file in $files) {
if ($PSCmdlet.ShouldProcess($file.FullName, "Delete")) {
Remove-Item -Path $file.FullName -Force
Write-Verbose "Deleted: $($file.Name)"
}
}
}
# Dry run with -WhatIf
Remove-TempFiles -FolderPath "C:\Temp" -WhatIf
# Verbose output
Remove-TempFiles -FolderPath "C:\Temp" -Verbose
Typed Parameters
Specifying parameter types enforces the correct data type and gives better error messages.
function Get-CircleArea {
param (
[double]$Radius
)
$area = [math]::PI * $Radius * $Radius
return [math]::Round($area, 4)
}
$area = Get-CircleArea -Radius 5
Write-Host "Area of circle: $area"
Output:
Area of circle: 78.5398
Mandatory Parameters
function Get-UserInfo {
param (
[Parameter(Mandatory=$true)]
[string]$Username,
[string]$Domain = "local"
)
Write-Host "Looking up: $Username@$Domain"
}
# This will prompt for Username if not provided
Get-UserInfo -Username "admin"
Get-UserInfo -Username "ravi" -Domain "company.com"
Output:
Looking up: admin@local
Looking up: ravi@company.com
Recursive Function
A recursive function calls itself. A classic example is calculating a factorial.
function Get-Factorial {
param ([int]$n)
if ($n -le 1) {
return 1
}
return $n * (Get-Factorial -n ($n - 1))
}
Write-Host "5! = $(Get-Factorial -n 5)" # 120
Write-Host "6! = $(Get-Factorial -n 6)" # 720
Output:
5! = 120
6! = 720
Function Scope
$globalVar = "I am global"
function Test-Scope {
$localVar = "I am local"
Write-Host $globalVar # Accessible – global scope
Write-Host $localVar # Accessible – local scope
}
Test-Scope
Write-Host $globalVar # Accessible
Write-Host $localVar # Error – $localVar not accessible outside function
Real-World Example – Log Writer Function
function Write-Log {
param (
[string]$Message,
[string]$Level = "INFO",
[string]$LogFile = "C:\Logs\app.log"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logEntry = "[$timestamp] [$Level] $Message"
Write-Host $logEntry
# Also write to log file
Add-Content -Path $LogFile -Value $logEntry
}
Write-Log -Message "Script started"
Write-Log -Message "Processing data..." -Level "DEBUG"
Write-Log -Message "An error occurred" -Level "ERROR"
Output:
[2026-03-21 10:30:00] [INFO] Script started
[2026-03-21 10:30:01] [DEBUG] Processing data...
[2026-03-21 10:30:02] [ERROR] An error occurred
Summary
Functions eliminate code repetition and make scripts modular and maintainable. Parameters accept input. Default values handle optional arguments. The return keyword sends output back to the caller. Adding [CmdletBinding()] promotes a function to a full cmdlet with built-in switches like -WhatIf and -Verbose. Mandatory parameters force callers to supply critical values. Recursive functions solve problems that naturally repeat in smaller sub-steps. Together, these features make PowerShell functions as powerful as functions in any modern scripting language.
