# 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 November 10, 2026

## 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:

```powershell
# 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:

```powershell
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:

```powershell
.\move-receipts.ps1 > moved.txt
Get-Content moved.txt
```

```text
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:

```powershell
.\move-receipts.ps1 -Verbose
```

```text
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:

```powershell
.\move-receipts.ps1 -Destination "$HOME\terminal-practice\mover\backup-drvie"
$LASTEXITCODE
```

```text
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](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/11/8157623e05fe42e2ab1977a87b8224f8.webp)

## 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

- [Write-Output](https://www.ask-codey.com/glossary/write-output)
- [Write-Host](https://www.ask-codey.com/glossary/write-host)
- [Output Streams](https://www.ask-codey.com/glossary/output-streams)
- [CmdletBinding](https://www.ask-codey.com/glossary/cmdletbinding)
- [Redirection](https://www.ask-codey.com/glossary/redirection-powershell)

## Cheat sheets

- [Where Output Goes: \`Write-Output\`, \`Write-Host\` and Friends](https://www.ask-codey.com/cheat-sheets/powershell-output-streams-cheat-sheet)

## Related

- [\`try\`, \`catch\` and \`finally\`](https://www.ask-codey.com/lessons/powershell-try-catch)
- [Writing to Files: Set-Content, Add-Content and >](https://www.ask-codey.com/lessons/powershell-writing-to-files)
- [The Pipeline: |](https://www.ask-codey.com/lessons/powershell-the-pipeline)

Source: https://www.ask-codey.com/lessons/powershell-output-streams
