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-Outputor implicit output. The main data pipeline. Captured by assignment, pipes, and redirection. - Stream 2 — Error:
Write-Error. Non-terminating errors. Captured with2>redirection. - Stream 3 — Warning:
Write-Warning. Soft alerts. Captured with3>. - Stream 4 — Verbose:
Write-Verbose. Debug information. Shown with-Verboseor$VerbosePreference = 'Continue'. - Stream 5 — Debug:
Write-Debug. Developer debug info. Shown with-Debugflag. - 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$nullto$resultbecauseWrite-Hostbypasses the pipeline. Replace withWrite-Output 'data'for pipeline-compatible output, or withWrite-Verbosefor status messages. -
Write-Verbose needs -Verbose flag or $VerbosePreference: Calling a function without
-Verbosesuppresses all verbose output, even if the function body has manyWrite-Verbosecalls. This is by design — add[CmdletBinding()]to your functions to support the-Verboseparameter.
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.


