Where Output Goes: `Write-Output`, `Write-Host` and Friends

Write-Output sends a script's results down the pipeline, where the next command, a variable or a > file receives them, while Write-Host, Write-Warning, Write-Verbose and Write-Error send words for people to the screen, each on a channel of its own that > and the pipeline leave alone.

Journeyman · PowerShell · Updated

After this lesson you can

  • Choose between Write-Output for results the next command receives and Write-Host for words only for the screen
  • Report warnings, details and failures from a script with Write-Warning, Write-Verbose and Write-Error

Key takeaways

  • Write-Output sends results down the pipeline: the next command, a variable or a > file gets them.
  • Write-Host writes words for the person watching, in color if you like. The pipeline and > never get them.
  • Write-Warning prints WARNING: for something worth a look. Write-Verbose prints details only when you run the script with -Verbose.
  • Write-Error reports a failure in red, on the error channel, so it never ends up in your results.
  • [CmdletBinding()] above param() gives your script -Verbose and the other common parameters every cmdlet has.

You'd like a list of every receipt your mover moved, so you run .\move-receipts.ps1 > moved.txt. But the file also gets the chatty lines meant for you, Moved in front of every name, and, on a bad day, the error message too, filed as if it were a receipt. A script talks to two audiences: the person watching the screen, and whatever comes next, a file, a variable or another command. Tools that IT teams and developers share keep the two apart, and PowerShell gives each kind of message a channel of its own.

Results, and words for the screen

Think of a restaurant kitchen. Plates go through the pass to the dining room; "two minutes on table four!" is for the kitchen only. In a script, Write-Output sends plates: results that go down the pipeline, to the next command, a variable or a > file. Write-Host is for the kitchen: words that only ever reach the screen, in color if you like.

Here is the mover with its messages sorted out. Each receipt it moves is a result, so it outputs only the name. Everything else is for people:

# move-receipts.ps1: moves every receipt in the inbox to the backup drive
[CmdletBinding()]
param($Destination = "$HOME\terminal-practice\mover\backup-drive")
$inbox = "$HOME\terminal-practice\mover\inbox"
Write-Host "Moving receipts to $Destination" -ForegroundColor Cyan
try {
    foreach ($file in Get-ChildItem $inbox -File) {
        $to = "$Destination\$($file.Name)"
        if (Test-Path $to) {
            Write-Warning "$($file.Name) is already there. Left it in the inbox."
            continue
        }
        Write-Verbose "Copying $($file.Name) to $Destination"
        Copy-Item -Path $file.FullName -Destination $to -ErrorAction Stop
        Remove-Item -Path $file.FullName
        Write-Output $file.Name
    }
}
catch {
    Write-Error "Couldn't copy $($file.Name): $($_.Exception.Message) It is still in the inbox."
    exit 1
}

The Test-Path check is new, and it's about never losing a file: Copy-Item replaces a file of the same name without asking, which would wipe out the copy already on the backup drive.

To try it, run the practice-folder lines from Reading Errors, and -ErrorAction, then empty the pretend backup drive and put last week's gas receipt on it:

Remove-Item backup-drive\*
Copy-Item inbox\2026-10-05-gas.pdf -Destination backup-drive

Now send the results into a file, and read it:

.\move-receipts.ps1 > moved.txt
Get-Content moved.txt
Moving receipts to C:\Users\Sam\terminal-practice\mover\backup-drive
WARNING: 2026-10-05-gas.pdf is already there. Left it in the inbox.
2026-10-03-groceries.pdf
2026-10-09-pharmacy.pdf

The first two lines appeared on the screen while the script ran: > didn't take them. The file holds only the results, the two receipts that moved. A pipeline works the same way: .\move-receipts.ps1 | Measure-Object counts 2.

Warnings and details

Write-Warning is for "done, but have a look": it prints in yellow, starting WARNING:. Write-Verbose is for details you want only sometimes: it prints nothing until you run the script with -Verbose. That parameter comes from the line [CmdletBinding()] above param(), which gives your script the common parameters every cmdlet has, -Verbose and -ErrorAction among them. Put the receipts back as before, then:

.\move-receipts.ps1 -Verbose
Moving receipts to C:\Users\Sam\terminal-practice\mover\backup-drive
VERBOSE: Copying 2026-10-03-groceries.pdf to C:\Users\Sam\terminal-practice\mover\backup-drive
2026-10-03-groceries.pdf
WARNING: 2026-10-05-gas.pdf is already there. Left it in the inbox.
VERBOSE: Copying 2026-10-09-pharmacy.pdf to C:\Users\Sam\terminal-practice\mover\backup-drive
2026-10-09-pharmacy.pdf

Your own errors: `Write-Error`

In try, catch and finally, the message about a failed copy went out with Write-Output, so > moved.txt would have filed it as a receipt. A failure belongs on the error channel: Write-Error prints it in red, adds it to $Error, and keeps it out of your results, like any cmdlet's error. Run it with the misspelled folder:

.\move-receipts.ps1 -Destination "$HOME\terminal-practice\mover\backup-drvie"
$LASTEXITCODE
Moving receipts to C:\Users\Sam\terminal-practice\mover\backup-drvie
Write-Error: Couldn't copy 2026-10-05-gas.pdf: Could not find a part of the path 'C:\Users\Sam\terminal-practice\mover\backup-drvie\2026-10-05-gas.pdf'. It is still in the inbox.
1

The gas receipt was the only one left in the inbox, so it's the one the message names. Before the colon, PowerShell names the command that reported the error: here, Write-Error itself.

A script as a kitchen with one pass and one speaker: Write-Output sends plates, the moved receipts' names, through the pass to the next command or a file; Write-Host, Write-Warning, Write-Verbose and Write-Error all send their words to the screen, where the person running the script reads them

Which one?

PowerShell calls these channels streams. You'll use these five:

Command Use it for Where it goes
Write-Output Results: things the next command, a variable or a file should get The pipeline
Write-Host Words for the person watching, such as a heading, in color if you like The screen only
Write-Warning It worked, but something is worth a look The screen, as WARNING:
Write-Verbose Details, shown only with -Verbose The screen, as VERBOSE:
Write-Error It failed The screen in red, and $Error

A quick test: if a file or the next command should get it, Write-Output. If only a person should read it, one of the others. All five work the same in Windows PowerShell 5.1 and on a Mac or Linux.

Check yourself

2 questions to try on the lesson page.

So what

Results down the pipeline, words for people on the screen: keep them apart, and anyone can save, count or pipe your script's output and still read every warning.

Key terms

Cheat sheets

Related