Skip to content

PowerShell Input and Output

How PowerShell's multi-stream architecture separates input/output (I/O) for scripts, including Read-Host for user prompts, Write-Output vs. Write-Host for pipeline vs. console output, and formatting cmdlets like Format-Table.

PowerShell manages input and output (I/O) using a multi-stream architecture. Unlike traditional shells that treat all console communication as a single, unformatted text stream, PowerShell separates structured pipeline data, interactive user prompts, errors, warnings, diagnostic messages, and host presentation into distinct, controllable communication channels. Understanding these streams is essential for writing scripts that behave predictably in both interactive and automated contexts.

Capturing User Input with Read-Host

The Read-Host cmdlet pauses script execution and prompts the user to enter a line of input from the console. By default, it returns the input as a standard System.String.

Example of Read-Hostpowershell
$TargetServer = Read-Host -Prompt "Enter the destination server name"
Write-Output "Connecting to $TargetServer..."
Outputplaintext
Enter the destination server name: web-prod-02
Connecting to web-prod-02...

A simpler hello-name example:

read-host.ps1powershell
$name = Read-Host -Prompt "Enter your name"
Write-Output "Hello, $name!"

where:

  • -Prompt displays a message before the input cursor.
  • The typed value is returned as a string and stored in $name.
Consolepowershell
./read-host.ps1
Outputplaintext
Enter your name: Tom
Hello, Tom!

Masking Sensitive Input

When capturing passwords, API tokens, or secrets, use the -AsSecureString parameter to encrypt the input in memory as a System.Security.SecureString, or -MaskInput (available in PowerShell 6+) to mask user keystrokes with asterisks without converting the type:

read-credentials.ps1powershell
$SecurePassword = Read-Host -Prompt "Enter API Key" -AsSecureString

[PSCustomObject]@{
    InputCaptured = $true
    TypeStored    = $SecurePassword.GetType().Name
    LengthChars   = $SecurePassword.Length
}

where:

  • -Prompt specifies the message string displayed to the user.
  • -AsSecureString stores input as an encrypted byte array in memory rather than plain text.
Consolepowershell
pwsh ./read-credentials.ps1
Outputplaintext
Enter API Key: ****************

InputCaptured TypeStored   LengthChars
------------- ----------   -----------
         True SecureString          16

A minimal password prompt example:

Consolepowershell
$password = Read-Host -Prompt "Enter password" -AsSecureString

Output Streams: Write-Output vs. Write-Host vs. Write-Verbose

PowerShell maintains six numbered output streams to isolate different types of runtime messages:

Stream Number Name Typical Cmdlet Purpose
1 Success / Pipeline Write-Output Emits data objects into the pipeline for downstream commands or variable capture.
2 Error Write-Error Emits non-terminating error records.
3 Warning Write-Warning Emits warning messages highlighted with yellow text.
4 Verbose Write-Verbose Emits detailed operational messages when enabled by -Verbose.
5 Debug Write-Debug Emits interactive troubleshooting details.
6 Information / Host Write-Host Writes presentation text directly to the console UI.

Write-Output (The Pipeline Stream)

Write-Output writes objects to Stream 1 (the Success Pipeline). Any object emitted to Stream 1 can be piped to other cmdlets, stored in a variable, or redirected:

Example of Write-Outputpowershell
$result = Write-Output "Database online"
$result
Outputplaintext
Database online

In PowerShell, bare expressions and unassigned variable declarations implicitly call Write-Output. Writing "Database online" on a line by itself produces the exact same result.

Write-Host (The Host Interface)

Write-Host writes directly to the console host (Stream 6). It is intended exclusively for interactive console output and user interface formatting (such as colored status text).

Example of Write-Hostpowershell
$result = Write-Host "Database online" -ForegroundColor Green
$result -eq $null
Outputplaintext
Database online
True

Notice that $result is $null. Because Write-Host bypasses Stream 1, its output cannot be captured into a variable or piped to another cmdlet.

Write-Verbose (Diagnostic Messaging)

Write-Verbose sends messages to Stream 4. By default, verbose messages are suppressed by the $VerbosePreference variable (set to 'SilentlyContinue'). They become visible only when you pass the -Verbose common parameter to an advanced script/function, or manually set $VerbosePreference = 'Continue':

verbose-demo.ps1powershell
[CmdletBinding()]
param ()

Write-Verbose "Performing pre-flight disk capacity checks..."
Write-Output "Storage verification successful."
Consolepowershell
pwsh ./verbose-demo.ps1 -Verbose
Outputplaintext
VERBOSE: Performing pre-flight disk capacity checks...
Storage verification successful.

Comparison Table

Cmdlet Stream Goes to Pipeline? Typical Use
Write-Output Success stream (1) Yes Returning data for further processing or capture
Write-Host Host/console only No Displaying messages directly to the user
Write-Verbose Verbose stream (4) No (unless -Verbose) Optional diagnostic detail for troubleshooting
write-comparison.ps1powershell
Write-Output "This goes into the pipeline"
Write-Host "This only appears on screen" -ForegroundColor Cyan
Write-Verbose "This is hidden unless -Verbose is used" -Verbose
Consolepowershell
./write-comparison.ps1
Outputplaintext
This goes into the pipeline
This only appears on screen
VERBOSE: This is hidden unless -Verbose is used

Directing and Suppressing Output: Out-File and Out-Null

Writing Output to Files: Out-File

The Out-File cmdlet captures Stream 1 pipeline output and writes it to a file on disk. It preserves the exact visual layout produced in the console:

Example of Out-Filepowershell
Get-Process | Out-File -FilePath "processes.txt"

where:

  • -FilePath specifies the destination file.
  • By default, Out-File overwrites the file; use -Append to add to existing content instead.

A more detailed example with explicit encoding:

Consolepowershell
Get-Service -Name "wuauserv" | Out-File -FilePath "$PSScriptRoot\service-state.txt" -Encoding utf8

Key parameters:

  • -FilePath: Specifies the destination path.
  • -Append: Appends data to an existing file instead of overwriting it.
  • -Encoding: Controls character encoding (e.g., utf8, ascii, unicode).
  • -Width: Specifies the character width limit before text wraps (defaults to console width).

Suppressing Output: Out-Null

Out-Null discards pipeline output entirely, useful when a cmdlet's return value isn't needed but you don't want it cluttering the console.

Example of Out-Nullpowershell
New-Item -ItemType Directory -Path "C:\Temp\Logs" | Out-Null

where:

  • Without Out-Null, New-Item would print details about the newly created folder to the console.
  • Out-Null suppresses that output while still executing the command's side effect (creating the folder).

Suppression Techniques Compared

Administrative cmdlets and .NET methods often emit status messages, collections, or numeric values that you do not want in your script's output stream. You can discard unwanted pipeline data using several techniques:

suppress-output.ps1powershell
New-Item -ItemType Directory -Path "$env:TEMP\TestDir" -Force | Out-Null

$null = New-Item -ItemType Directory -Path "$env:TEMP\TestDir2" -Force

$list = [System.Collections.Generic.List[string]]::new()
[void]$list.Add("Cluster01")

where:

  • | Out-Null redirects Stream 1 to an internal discard sink.
  • $null = ... and [void]... prevent the pipeline engine from generating object wrappers entirely, offering better performance inside tight loops.

Formatting Output: Format-Table, Format-List, and Format-Wide

PowerShell includes formatting cmdlets that transform objects into visual layout instructions for terminal display, without altering the underlying data.

1. Format-Table (ft)

Presents data in an aligned columnar layout. Best suited for displaying collections of objects that have a small number of properties.

Example of Format-Tablepowershell
Get-Service | Select-Object -First 3 | Format-Table -Property Name, Status -AutoSize
Outputplaintext
Name          Status
----          ------
AJRouter     Stopped
ALG          Stopped
AppIDSvc     Running

Another example using -Property on selected processes:

Consolepowershell
Get-Process -Name "pwsh", "explorer" | Format-Table -Property Id, ProcessName, WorkingSet64 -AutoSize
Outputplaintext
   Id ProcessName WorkingSet64
   -- ----------- ------------
12948 pwsh           141754368
 4912 explorer       204890112

where -AutoSize calculates column widths based on the actual size of the data rather than truncating values at fixed intervals.

2. Format-List (fl)

Presents each property on its own line in a vertical key-value list. Best suited for inspecting objects with many properties or properties containing long text strings.

Example of Format-Listpowershell
Get-Service -Name "Spooler" | Format-List -Property *
Outputplaintext
UserName            : LocalSystem
Description         : This service spools print jobs and handles interaction with the printer.  If you turn off this service, you won't be able to print
                      or see your printers.
DelayedAutoStart    : False
BinaryPathName      : C:\Windows\System32\spoolsv.exe
StartupType         : Automatic
Name                : Spooler
RequiredServices    : {RPCSS, http}
CanPauseAndContinue : False
CanShutdown         : False
CanStop             : True
DisplayName         : Print Spooler
DependentServices   : {Fax}
MachineName         : .
ServiceName         : Spooler
ServicesDependedOn  : {RPCSS, http}
StartType           : Automatic
ServiceHandle       :
Status              : Running
ServiceType         : Win32OwnProcess, InteractiveProcess
Site                :
Container           :

Another example using specific properties:

Consolepowershell
Get-Process -Name "pwsh" | Format-List -Property ProcessName, Id, Path, StartTime
Outputplaintext
ProcessName : pwsh
Id          : 12948
Path        : C:\Program Files\PowerShell\7\pwsh.exe
StartTime   : 10/24/2026 8:30:15 AM

Use Format-List -Property * to display all available properties on an object.

3. Format-Wide (fw)

Displays a single property per object, arranged in multiple columns. This is useful for quickly scanning names.

Example of Format-Widepowershell
Get-Process | Select-Object -First 6 | Format-Wide -Property Name -Column 3
Outputplaintext
chrome                        pwsh                          explorer
notepad                       svchost                       dwm

Using -Noun filtering with Get-Command:

Consolepowershell
Get-Command -Noun Process | Format-Wide -Column 3
Outputplaintext
Debug-Process                Get-Process                  Start-Process
Stop-Process                 Wait-Process

Practical Example: Automated Node Audit with Multi-Stream Output

The following script combines interactive user input, stream isolation (Write-Verbose, Write-Warning, Write-Host), pipeline object output, and optional file logging:

audit-node-environment.ps1powershell
[CmdletBinding()]
param (
    [string]$LogPath = "$PSScriptRoot\node-audit.log"
)

$Threshold = Read-Host -Prompt "Enter minimum disk alert threshold (GB)"

Write-Verbose "Validating input threshold: $Threshold"
if (-not ($Threshold -as [int])) {
    Write-Warning "Invalid threshold supplied. Falling back to default baseline of 20 GB."
    $Threshold = 20
} else {
    $Threshold = [int]$Threshold
}

Write-Verbose "Querying logical disks from CIM..."
$Disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"

$Results = foreach ($disk in $Disks) {
    $freeGB = [math]::Round($disk.FreeSpace / 1GB, 2)
    $isLow  = $freeGB -lt $Threshold

    if ($isLow) {
        Write-Host "ALERT: Volume $($disk.DeviceID) has only $freeGB GB remaining!" -ForegroundColor Red
    }

    [PSCustomObject]@{
        DriveID      = $disk.DeviceID
        FreeGB       = $freeGB
        LowThreshold = $Threshold
        NeedsAction  = $isLow
    }
}

$Results | Format-Table -AutoSize | Out-File -FilePath $LogPath -Encoding utf8
Write-Host "Audit log written to: $LogPath" -ForegroundColor Green

$Results

where:

  • [CmdletBinding()] turns the script into an advanced function, enabling -Verbose.
  • Read-Host prompts the operator for a threshold.
  • Write-Verbose reports operational progress without polluting the output stream.
  • Write-Warning emits an execution warning if parsing fails.
  • Write-Host prints colored alert notifications directly to the console.
  • Out-File saves the formatted table report to disk.
  • $Results at the end emits structured objects to Stream 1 for downstream consumption.

Execute the script from the console:

Consolepowershell
pwsh ./audit-node-environment.ps1 -Verbose
Outputplaintext
Enter minimum disk alert threshold (GB): 50
VERBOSE: Validating input threshold: 50
VERBOSE: Querying logical disks from CIM...
ALERT: Volume C: has only 34.12 GB remaining!
Audit log written to: C:\Scripts\node-audit.log

DriveID FreeGB LowThreshold NeedsAction
------- ------ ------------ -----------
C:       34.12           50        True
D:      512.80           50       False
Navigation