Why Variables Matter in Everyday Automation
Automation usually follows a simple pattern: get some information, store it, make a decision, then act. Variables are how you store information so you can reuse it later in the script without re-running commands or retyping values.
In PowerShell, variables start with $. Use meaningful names so your future self (or a teammate) can understand what the script is doing at a glance.
$computerName = $env:COMPUTERNAME
$logFolder = 'C:\Logs'
$maxSizeMB = 200Notice the consistent indentation and alignment. You do not have to align assignments, but consistency improves readability.
Basic Data Types You’ll Use All the Time
Strings
Strings are text values. Use single quotes for literal text and double quotes when you want variable expansion.
$literalPath = 'C:\Temp\Reports'
$userPath = "C:\Users\$env:USERNAME\Desktop"Integers (numbers)
Numbers are used for counts, thresholds, and comparisons.
Continue in our app.
You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.
Or continue reading below...Download the app
$retryCount = 3
$timeoutSec = 30Booleans
Booleans are $true or $false. They’re often the result of a test, or used as flags.
$isDryRun = $true # set to $false to actually perform changesDates and times
Dates are useful for timestamps and age checks.
$now = Get-Date
$cutoff = (Get-Date).AddDays(-7)Quick type awareness
You can inspect a value’s type when you’re unsure what you’re working with.
$now.GetType().FullNameStoring Command Results in Variables
A common pattern is to run a command once, store the result, then use it multiple times.
Example: Capture a service and act on it
Step-by-step:
- Store the service object in a variable.
- Check its current status.
- Only take action if needed.
$serviceName = 'Spooler'
$service = Get-Service -Name $serviceName
if ($service.Status -ne 'Running') {
# Start only if not already running
Start-Service -Name $serviceName
}This avoids unnecessary actions and makes the script safe to run repeatedly.
Example: Store a list of items from a command
When a command returns multiple objects, the variable holds a collection.
$stoppedServices = Get-Service | Where-Object Status -eq 'Stopped'
$stoppedServices.CountStoring the result lets you reuse it (for counting, reporting, or taking action) without re-running the query.
Arrays: Iterating Over Multiple Items
An array is an ordered list. Use arrays when you have “a bunch of similar things” to process: computer names, folders, service names, file extensions, etc.
Create an array
$foldersToCheck = @(
'C:\Temp',
'C:\Logs',
'C:\Tools'
)Loop through items with foreach
Step-by-step:
- Define the list.
- Iterate over each item.
- Run the same logic for each.
$foldersToCheck = @('C:\Temp', 'C:\Logs', 'C:\Tools')
foreach ($folder in $foldersToCheck) {
Write-Host "Checking: $folder"
}Use a singular loop variable name ($folder) for a plural collection ($foldersToCheck). This small naming habit improves readability.
Common pattern: Check whether a path exists before creating it
This is one of the most practical if/else patterns in PowerShell.
$targetFolder = 'C:\Logs\App1'
if (-not (Test-Path -Path $targetFolder)) {
# Create the folder only if it does not exist
New-Item -Path $targetFolder -ItemType Directory | Out-Null
}Test-Path returns a boolean. The -not flips it, so the block runs only when the folder is missing.
Combine arrays + path checks
$foldersToEnsure = @(
'C:\Logs\App1',
'C:\Logs\App2',
'C:\Logs\App3'
)
foreach ($folder in $foldersToEnsure) {
if (-not (Test-Path -Path $folder)) {
New-Item -Path $folder -ItemType Directory | Out-Null
}
}Hashtables: Simple, Readable “Key = Value” Data
A hashtable stores pairs: a key and its value. Use it when you want to label values (instead of relying on array positions) or when you want quick lookups.
Create and read a hashtable
$settings = @{
LogRoot = 'C:\Logs\App1'
MaxSizeMB = 200
RetainDays = 14
EnableDebug = $false
}
$settings.LogRoot
$settings['MaxSizeMB']Dot notation is convenient for simple keys. Bracket notation is useful when keys contain spaces or special characters.
Example: Use a hashtable to drive decisions
Step-by-step:
- Define settings once.
- Use them in conditions.
- Act only when conditions are met.
$settings = @{
LogRoot = 'C:\Logs\App1'
MaxSizeMB = 200
RetainDays = 14
}
if (-not (Test-Path -Path $settings.LogRoot)) {
New-Item -Path $settings.LogRoot -ItemType Directory | Out-Null
}Simple Logic with if/elseif/else
Conditional logic lets your script make decisions instead of doing the same thing every time. PowerShell conditions evaluate to $true or $false.
Basic if/else
$freeGB = 12
if ($freeGB -lt 10) {
Write-Host 'Low disk space: take action'
}
else {
Write-Host 'Disk space looks OK'
}Multiple branches with elseif
$cpuLoad = 85
if ($cpuLoad -ge 90) {
Write-Host 'CPU load is critical'
}
elseif ($cpuLoad -ge 75) {
Write-Host 'CPU load is elevated'
}
else {
Write-Host 'CPU load is normal'
}Common comparison operators
| Operator | Meaning | Example |
|---|---|---|
-eq | equals | $x -eq 5 |
-ne | not equals | $status -ne 'Running' |
-lt | less than | $n -lt 10 |
-le | less than or equal | $n -le 10 |
-gt | greater than | $n -gt 10 |
-ge | greater than or equal | $n -ge 10 |
-like | wildcard match | $name -like 'SQL*' |
-match | regex match | $text -match '^ERR' |
Act Only When a Condition Is Met
Many automation tasks should be “no-op” when there’s nothing to do. This makes scripts safe to run on a schedule.
Example: Only create a folder when missing (with a message)
$targetFolder = 'C:\Temp\Daily'
if (Test-Path -Path $targetFolder) {
Write-Host "Already exists: $targetFolder"
}
else {
New-Item -Path $targetFolder -ItemType Directory | Out-Null
Write-Host "Created: $targetFolder"
}Example: Only stop a service if it’s running
$serviceName = 'wuauserv'
$service = Get-Service -Name $serviceName
if ($service.Status -eq 'Running') {
# Stop only when running
Stop-Service -Name $serviceName
}Example: Guard clauses to keep code readable
A guard clause exits early when a requirement isn’t met. This can reduce nesting and keep scripts easier to scan.
$sourceFolder = 'C:\Temp\Input'
if (-not (Test-Path -Path $sourceFolder)) {
Write-Host "Source folder missing: $sourceFolder"
return
}
# Continue only when the folder exists
Write-Host "Processing files in: $sourceFolder"Readable Code: Naming, Indentation, and Comments
Meaningful variable names
Prefer descriptive names over short ones. Compare:
# Harder to read
$x = 'C:\Logs'
$y = 14
# Easier to read
$logRootPath = 'C:\Logs'
$retainDays = 14Consistent indentation
Indent inside if, foreach, and other blocks. Avoid mixing styles within the same script.
foreach ($folder in $foldersToEnsure) {
if (-not (Test-Path -Path $folder)) {
New-Item -Path $folder -ItemType Directory | Out-Null
}
}Brief comments that explain “why”
Comments are most valuable when they explain intent or constraints, not when they restate the obvious.
$archiveFolder = 'C:\Logs\Archive'
# Keep archives separate so cleanup jobs can target one location
if (-not (Test-Path -Path $archiveFolder)) {
New-Item -Path $archiveFolder -ItemType Directory | Out-Null
}Mini-Recipe: A Small, Practical Automation Script
This example combines variables, arrays, hashtables, looping, and if/else into a single purpose-driven task: ensure folders exist and apply simple rules per folder.
Step-by-step:
- Define folder rules in a hashtable.
- Loop through each rule.
- Create missing folders.
- Print a message only when an action is taken.
$folderRules = @{
'C:\Logs\App1' = @{ Ensure = $true; Note = 'Main app logs' }
'C:\Logs\App2' = @{ Ensure = $true; Note = 'Secondary app logs' }
'C:\Logs\Old' = @{ Ensure = $false; Note = 'Deprecated location' }
}
foreach ($path in $folderRules.Keys) {
$rule = $folderRules[$path]
if (-not $rule.Ensure) {
# Skip paths that are intentionally not managed
continue
}
if (-not (Test-Path -Path $path)) {
New-Item -Path $path -ItemType Directory | Out-Null
Write-Host "Created folder: $path ($($rule.Note))"
}
}