Skip to content
February 27, 2026 • Junior (1-3 years) How-To

PowerShell Error Handling Best Practices

By Last updated

Write robust PowerShell scripts with proper error handling. Try/Catch, -ErrorAction, and logging strategies.

Free PDF

Top 10 Intune and Autopilot Enrollment Errors: Causes and Fixes

A free cheat sheet covering ten enrollment errors, each with the symptom, the most likely cause, the fix, and a link to the full guide.

  • Ten real error codes and failures, including 0x80180014, 0x8018002b, 0x801c03f3, 0x800705b4, the ODJConnector logon failure, and the Win32 detection error 0x87d1041c.
  • Every cause and fix checked against Microsoft's own documentation.
  • A link from each entry to the full zakitpro.com article.

You get the free PDF. By subscribing you also agree to receive occasional emails from zakitpro about Intune and Autopilot troubleshooting. Emails are sent through MailerLite. You can unsubscribe anytime with the link in every email. See the privacy page for how your email is handled.

Step-by-step guide

PowerShell Error Handling Best Practices

Bad error handling makes scripts fragile. Good error handling makes them professional. Here’s how to write PowerShell that fails gracefully.

The Basics

-ErrorAction Parameter

# Different levels
Stop      # Throw exception (use with Try/Catch)
Continue  # Write to $error and continue (default)
SilentlyContinue # Suppress error message
Inquire   # Ask user what to do

# Examples
Get-Item C:\Missing -ErrorAction Stop
Get-Item C:\Missing -ErrorAction SilentlyContinue

Try/Catch/Finally

try {
    # Risky operation
    Get-Content "C:\important.txt" -ErrorAction Stop
    
    # Success path
    Write-Host "File found!"
}
catch {
    # What to do on failure
    Write-Host "Error: $($_.Exception.Message)"
    
    # Log the error
    $Error | Out-File "C:\Logs\errors.log" -Append
}
finally {
    # Always runs - cleanup
    Remove-Item $tempFile -ErrorAction SilentlyContinue
}

Types of Errors

Terminating vs Non-Terminating

# Terminating - stops execution
# Use -ErrorAction Stop to convert

# Non-terminating - continues
Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue

# Make terminating
$ErrorActionPreference = "Stop"

Catch Specific Errors

try {
    Get-ADUser "doesntexist"
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
    Write-Host "User not found"
}
catch [System.UnauthorizedAccessException] {
    Write-Host "Access denied"
}
catch {
    Write-Host "Unexpected error: $_"
}

Logging Errors

function Write-ErrorLog {
    param([string]$Message)
    
    $LogPath = "$env:TEMP\ScriptErrors.log"
    $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    
    "$Timestamp - $Message" | Out-File $LogPath -Append
}

# Usage
try {
    Invoke-RestMethod "https://api.example.com/data" -ErrorAction Stop
}
catch {
    Write-ErrorLog "API call failed: $($_.Exception.Message)"
    throw
}

Validation Patterns

# Pre-flight checks
function Install-App {
    param([string]$InstallerPath)
    
    # Validate input
    if (-not (Test-Path $InstallerPath)) {
        throw "Installer not found: $InstallerPath"
    }
    
    # Validate disk space
    $FreeSpace = (Get-PSDrive C).Free
    if ($FreeSpace -lt 1GB) {
        throw "Insufficient disk space"
    }
    
    # Proceed with install
}

Retry Logic

function Invoke-WithRetry {
    param(
        [scriptblock]$ScriptBlock,
        [int]$MaxAttempts = 3,
        [int]$DelaySeconds = 5
    )
    
    for ($i = 1; $i -le $MaxAttempts; $i++) {
        try {
            & $ScriptBlock -ErrorAction Stop
            return
        }
        catch {
            if ($i -eq $MaxAttempts) {
                throw "Failed after $MaxAttempts attempts: $_"
            }
            Write-Host "Attempt $i failed, retrying..."
            Start-Sleep -Seconds $DelaySeconds
        }
    }
}

# Usage
Invoke-WithRetry -ScriptBlock {
    Test-NetConnection -ComputerName "api.example.com" -Port 443
} -MaxAttempts 3 -DelaySeconds 5

$PSItem vs $_

# Both work the same
catch {
    $_.Exception.Message      # The error message
    $_.Exception.GetType()    # Exception type
    $_.ScriptStackTrace      # Where it happened
    $_.TargetObject           # What failed
}

Common Mistakes

❌ Bad:

Get-Item C:\file.txt
if ($?) { Write-Host "Success" }

✅ Good:

try {
    Get-Item C:\file.txt -ErrorAction Stop
    Write-Host "Success"
}
catch {
    Write-Host "Failed"
}

Wrap-Up

Always assume things can fail. Use Try/Catch, log errors, and validate inputs. Your future self will thank you.

Questions? Drop them below!

Free PDF

Top 10 Intune and Autopilot Enrollment Errors: Causes and Fixes

A free cheat sheet covering ten enrollment errors, each with the symptom, the most likely cause, the fix, and a link to the full guide.

  • Ten real error codes and failures, including 0x80180014, 0x8018002b, 0x801c03f3, 0x800705b4, the ODJConnector logon failure, and the Win32 detection error 0x87d1041c.
  • Every cause and fix checked against Microsoft's own documentation.
  • A link from each entry to the full zakitpro.com article.

You get the free PDF. By subscribing you also agree to receive occasional emails from zakitpro about Intune and Autopilot troubleshooting. Emails are sent through MailerLite. You can unsubscribe anytime with the link in every email. See the privacy page for how your email is handled.

#powershell #error-handling #scripting #best-practices