PowerShell Scripting for Windows Admins: Variables, Loops and Functions

6 min read

Learn PowerShell scripting fundamentals for Windows administration. Variables, conditionals, loops, functions, error handling and running scripts securely.

Share:TelegramX

PowerShell scripts automate repetitive tasks. Here's everything you need to go from copy-pasting commands to writing reusable scripts.


Variables and Data Types

# Strings
$name = "Windows Admin"
$path = "C:\Logs\output.txt"

# Numbers
$count = 42
$ram = 16.5

# Arrays
$servers = @("PC01", "PC02", "PC03")
$servers[0]   # first element: PC01
$servers.Count  # number of elements: 3

# Hashtables (key-value)
$config = @{
  Server = "192.168.1.10"
  Port   = 443
  SSL    = $true
}
$config.Server  # 192.168.1.10

# Boolean
$enabled = $true
$debug = $false

String Manipulation

# String interpolation
$computer = "PC01"
Write-Host "Connected to: $computer"

# String methods
"UPPERCASE".ToLower()       # lowercase
"  trim me  ".Trim()        # remove spaces
"path\to\file".Split("\")   # split to array
"hello world".Replace("world", "PowerShell")

# Here-strings (multiline)
$message = @"
Server: $computer
Status: Online
Time: $(Get-Date)
"@

Conditionals

# If / ElseIf / Else
$cpu = (Get-CimInstance Win32_Processor).LoadPercentage

if ($cpu -gt 90) {
  Write-Warning "CPU critical: $cpu%"
} elseif ($cpu -gt 70) {
  Write-Host "CPU high: $cpu%" -ForegroundColor Yellow
} else {
  Write-Host "CPU normal: $cpu%" -ForegroundColor Green
}

# Switch statement
switch ($cpu) {
  {$_ -gt 90} { "Critical"; break }
  {$_ -gt 70} { "High"; break }
  default      { "Normal" }
}

Loops

# ForEach-Object (pipeline)
Get-Service | Where-Object {$_.Status -eq "Stopped"} |
  ForEach-Object { Write-Host "Stopped: $($_.Name)" }

# foreach loop (faster for collections)
$computers = @("PC01", "PC02", "PC03")
foreach ($pc in $computers) {
  Write-Host "Checking $pc..."
  Test-NetConnection $pc -Port 3389 -EA 0
}

# For loop
for ($i = 1; $i -le 10; $i++) {
  Write-Host "Item $i"
}

# While loop
$attempts = 0
while ($attempts -lt 3) {
  $attempts++
  Write-Host "Attempt $attempts"
}

Functions

# Basic function
function Get-DiskInfo {
  param(
    [string]$DriveLetter = "C",
    [switch]$Verbose
  )
  
  $drive = Get-PSDrive $DriveLetter
  $freeGB = [math]::Round($drive.Free/1GB, 1)
  $usedGB = [math]::Round($drive.Used/1GB, 1)
  $totalGB = $freeGB + $usedGB
  $freePct = [math]::Round($freeGB/$totalGB * 100)
  
  if ($Verbose) {
    Write-Host "Drive ${DriveLetter}: Total=$totalGB GB, Used=$usedGB GB, Free=$freeGB GB ($freePct%)"
  }
  
  return [PSCustomObject]@{
    Drive  = $DriveLetter
    FreeGB = $freeGB
    UsedGB = $usedGB
    FreePct = $freePct
  }
}

# Usage
Get-DiskInfo -DriveLetter "C" -Verbose
$info = Get-DiskInfo "D"
if ($info.FreePct -lt 10) { Write-Warning "Low disk space on $($info.Drive)!" }

Error Handling

# Try/Catch/Finally
try {
  $result = Get-Content "C:\Missing\file.txt" -ErrorAction Stop
  Write-Host "File contents: $result"
}
catch [System.IO.FileNotFoundException] {
  Write-Warning "File not found"
}
catch {
  Write-Error "Unexpected error: $($_.Exception.Message)"
}
finally {
  Write-Host "Always runs"
}

# ErrorAction preference
$ErrorActionPreference = "Stop"  # treat all errors as terminating

# -EA 0 = silently continue (short for -ErrorAction SilentlyContinue)
Get-Service "NonExistent" -EA 0

Write Output

Write-Host "Normal output" -ForegroundColor Cyan
Write-Warning "This is a warning"
Write-Error "This is an error"
Write-Verbose "Debug info" -Verbose
Write-Progress -Activity "Processing" -Status "50%" -PercentComplete 50

# Output to file
"Log entry" | Out-File "C:\log.txt" -Append
Get-Process | Export-Csv "C:\processes.csv" -NoTypeInformation
Get-Service | ConvertTo-Json | Out-File "C:\services.json"

Summary

Variables: $name. Arrays: @(). Hashtables: @{}. Loops: foreach for collections, ForEach-Object for pipelines. Functions with param() for reusable code. Error handling with try/catch. Always use -ErrorAction Stop in functions to make errors catchable.

Frequently Asked Questions

What's the difference between Write-Host and Write-Output?

Write-Host writes directly to the console — output can't be piped or redirected. Write-Output (or just a bare value) writes to the pipeline — can be captured, piped, or redirected. Use Write-Output in functions, Write-Host for user messages.

My script works interactively but fails when scheduled — why?

Check: 1) Execution policy for the SYSTEM account, 2) relative paths (use $PSScriptRoot instead), 3) modules not loaded automatically, 4) credentials needed. Add full paths and explicit module imports.

How do I make a script accept parameters from command line?

param(
  [Parameter(Mandatory=$true)]
  [string]$ServerName,
  [int]$Port = 443,
  [switch]$Verbose
)
# Run: .\script.ps1 -ServerName "PC01" -Port 80

Related articles

💬 Leave a comment

Comments are moderated before publishing.

← All articles