PowerShell Write-Error, Write-Warning, Write-Verbose Guide

PowerShell Write-Error, Write-Warning, Write-Verbose Guide

PowerShell Tips Editor 3 min read
PowerShell Write-Error, Write-Warning, Write-Verbose Guide

PowerShell has six output streams, and mixing them up causes real problems: diagnostic messages pollute pipeline data, errors get swallowed, verbose output appears when it shouldn’t. The most common mistake is reaching for Write-Host for everything — but Write-Host output can’t be captured, redirected, or tested. Understanding the right cmdlet for each stream makes your scripts professional, predictable, and composable. This guide covers PowerShell Write-Error Write-Warning, all six streams, and when to use each.

The Six PowerShell Output Streams

PowerShell routes output to numbered streams, each with a specific purpose:

  • Stream 1 — Success: Write-Output or implicit output. The main data pipeline. Captured by assignment, pipes, and redirection.
  • Stream 2 — Error: Write-Error. Non-terminating errors. Captured with 2> redirection.
  • Stream 3 — Warning: Write-Warning. Soft alerts. Captured with 3>.
  • Stream 4 — Verbose: Write-Verbose. Debug information. Shown with -Verbose or $VerbosePreference = 'Continue'.
  • Stream 5 — Debug: Write-Debug. Developer debug info. Shown with -Debug flag.
  • Stream 6 — Information: Write-Information / Write-Host (PS5+). Informational messages separate from data.
# Redirect specific streams to files
Get-ChildItem 'C:\' -Recurse 2>'C:\Logs\errors.txt'           # Redirect error stream
Get-ChildItem 'C:\' -Recurse 3>'C:\Logs\warnings.txt'         # Redirect warning stream
Get-ChildItem 'C:\' -Recurse *>'C:\Logs\all-output.txt'       # Redirect all streams

Write-Output vs Write-Host

This is the most important distinction for writing pipeline-compatible scripts:

# Write-Output: goes to the success pipeline, can be captured
function Get-ServerList {
    Write-Output 'web01'
    Write-Output 'web02'
    Write-Output 'db01'
}

$servers = Get-ServerList   # $servers = @('web01','web02','db01')
$servers.Count              # 3

# Write-Host: goes to the display only — CANNOT be captured
function Show-Message {
    Write-Host "Processing started..."   # Always displays, never captured
    Write-Output 'Result'                # This is captured
}

$result = Show-Message   # $result = 'Result' only
# "Processing started..." still appeared on screen
3
Processing started...

Use Write-Output (or implicit output) for data your callers will use. Use Write-Host sparingly, only for display-only messages that should never be captured. In most scripts, Write-Verbose is a better choice than Write-Host for progress messages.

Write-Error for Non-Terminating Errors

Write-Error emits a non-terminating error to stream 2. Script execution continues unless -ErrorAction Stop or $ErrorActionPreference = 'Stop' is active:

# Write a non-terminating error
Write-Error 'Could not connect to database'
Write-Output 'Script continues after Write-Error'   # This runs

# Write-Error with a specific exception type
Write-Error -Message 'File not found' -Category ObjectNotFound

# In a function — caller decides whether to stop
function Test-Connection-Custom {
    param([string] $HostName)

    if (-not (Test-NetConnection $HostName -InformationLevel Quiet)) {
        Write-Error "Host unreachable: $HostName"
        return
    }
    Write-Output "Connected: $HostName"
}
Write-Error: Could not connect to database
Script continues after Write-Error

Write-Warning for Soft Alerts

Write-Warning displays a yellow-prefixed message on stream 3. It doesn’t affect execution flow:

# Soft warning — doesn't stop execution
Write-Warning 'Certificate expires in 7 days'
Write-Output 'Script continues'

# Warning with context
$diskFreeGB = 8
if ($diskFreeGB -lt 10) {
    Write-Warning "Low disk space: $diskFreeGB GB remaining on C:"
}

# Suppress warnings
Write-Warning 'Known issue — ignore this' -WarningAction SilentlyContinue

# Capture warnings
Write-Warning 'Test warning' -WarningVariable warnMsg
$warnMsg   # Contains the warning text
WARNING: Certificate expires in 7 days
Script continues
WARNING: Low disk space: 8 GB remaining on C:

Write-Verbose for Debug Info

Write-Verbose emits informational messages on stream 4 that only appear when verbose mode is active:

# Write-Verbose only shows when -Verbose is passed or preference is set
function Invoke-Backup {
    [CmdletBinding()]
    param([string] $Source, [string] $Destination)

    Write-Verbose "Starting backup: $Source -> $Destination"
    Copy-Item $Source $Destination -Force
    Write-Verbose "Backup complete"
    Write-Output "Backed up: $(Split-Path $Source -Leaf)"
}

# Silent run — no verbose output
Invoke-Backup -Source 'C:\Data' -Destination 'C:\Backup'

# Verbose run — shows all Write-Verbose messages
Invoke-Backup -Source 'C:\Data' -Destination 'C:\Backup' -Verbose
Backed up: Data

VERBOSE: Starting backup: C:\Data -> C:\Backup
Backed up: Data
VERBOSE: Backup complete

Write-Debug and $DebugPreference

# Write-Debug shows only when $DebugPreference is Continue or when -Debug flag is used
function Process-Data {
    [CmdletBinding()]
    param($InputData)

    Write-Debug "Input type: $($InputData.GetType().Name)"
    Write-Debug "Input count: $($InputData.Count)"
    # ... process
}

# Enable debug output for a session
$DebugPreference = 'Continue'
Process-Data -InputData @(1, 2, 3)
$DebugPreference = 'SilentlyContinue'   # Restore
DEBUG: Input type: Object[]
DEBUG: Input count: 3

Common Errors and Fixes

  • Write-Host output cannot be captured — use Write-Output: $result = Write-Host 'data' assigns $null to $result because Write-Host bypasses the pipeline. Replace with Write-Output 'data' for pipeline-compatible output, or with Write-Verbose for status messages.
  • Write-Verbose needs -Verbose flag or $VerbosePreference: Calling a function without -Verbose suppresses all verbose output, even if the function body has many Write-Verbose calls. This is by design — add [CmdletBinding()] to your functions to support the -Verbose parameter.

Related Cmdlets / See Also

Wrapping Up

Use Write-Output for pipeline data, Write-Error for recoverable errors, Write-Warning for soft alerts, and Write-Verbose for debug info that respects the -Verbose flag. Avoid Write-Host for anything that needs to be captured or tested. Your next step: review your most-used function and replace any Write-Host status messages with Write-Verbose calls inside a [CmdletBinding()] function.

Send-Item -To