Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

ProgressPreference Not Working in Redirects?

Wondering why ProgressPreference outputs don’t show when redirecting streams in PowerShell? Learn the reason and how to capture progress correctly.
PowerShell terminal showing missing progress bar due to ProgressPreference when redirecting output PowerShell terminal showing missing progress bar due to ProgressPreference when redirecting output
  • 🤯 Write-Progress bypasses normal output streams and writes directly to the host UI.
  • 🔄 $ProgressPreference only determines if progress is shown—not where it's sent.
  • 📁 Redirecting or capturing standard output won’t catch Write-Progress messages.
  • 🧪 Good alternatives include using Write-Output, Write-Verbose, or Write-Information.
  • 🛠️ Custom host UI elements or conditional logic can make scripts stronger and easier to test.

Understanding $ProgressPreference and Redirecting Streams in PowerShell

If you’ve written a PowerShell script with a good progress bar using Write-Progress, only to find that the progress disappears when redirecting output to a file, you are right to notice this. It is not easy to capture PowerShell progress output. This is because PowerShell keeps host visual output separate from other output data. This guide will explain why $ProgressPreference does not work well with redirection. And then we will look at how PowerShell manages different output streams. We will also cover ways to redirect streams, fake progress, or capture output for scripts and automated tasks.


What Is $ProgressPreference in PowerShell?

PowerShell includes some built-in preference variables that affect script behavior. Among these, $ProgressPreference controls if Write-Progress shows anything. It tells PowerShell to show progress, hide it, or give an error when it sees progress messages.

Main Modes of $ProgressPreference

Mode Description
Continue (Default) Shows progress indicators in the host interface.
SilentlyContinue Hides all Write-Progress calls, showing nothing.
Stop Gives an error when Write-Progress is called.
Inquire Asks the user before running the progress call.
Ignore Does not show or interact with progress in any way.

You can change the mode at any time with a simple assignment:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

$ProgressPreference = 'SilentlyContinue'

But keep this in mind: Even when Write-Progress messages are allowed (using Continue), you cannot redirect or capture them like other output or error messages.


PowerShell Streams: A Quick Look at How Output Is Handled

PowerShell is different because it uses many streams for various types of messages. Other shells do not do this. PowerShell lets you control exactly where each message goes.

Overview of PowerShell Streams

Stream # Name Description
1 Output Standard data results from pipeline commands.
2 Error Exceptions, script errors, and stopping/non-stopping errors.
3 Warning Warnings shown to the user with Write-Warning.
4 Verbose More detailed output using Write-Verbose.
5 Debug Diagnostic messages sent with Write-Debug.
6 Information Rich data captured with Write-Information.
N/A Progress Special UI messages managed with Write-Progress, skipping the stream.

The progress stream is not part of the regular numbered streams. It skips the normal output channels. Instead, it talks straight to the host interface using the .NET class System.Management.Automation.Host.PSHostUserInterface. This design lets progress messages show up clearly in the console. It keeps them out of logs or pipelines. But it also makes them hard to capture.


Why Redirecting Progress Output Doesn’t Work

Progress bars do not show up in redirected output. The main reason is that they are not part of any normal stream. You can capture output, error, and verbose messages with >, 2>, or *>. But progress messages are tied to the user interface.

Example

Script:

Write-Progress -Activity "Testing" -Status "50% Complete" -PercentComplete 50

Redirection:

.\myscript.ps1 > log.txt

You might expect the progress bar to show up in log.txt. But it does not. Nothing gets captured. This is because Write-Progress never sends anything to standard output or any other stream. PowerShell simply calls $Host.UI.WriteProgress() instead.

In short, redirection cannot capture progress messages. They are not part of a stream.


Practical Example: Testing Stream Redirection

Let's look at an example to see how PowerShell streams work when you redirect them.

Test Script

for ($i = 1; $i -le 5; $i++) {
    Write-Progress -Activity "Processing" -PercentComplete ($i * 20)
    Start-Sleep -Milliseconds 300
    "Step $i complete"
}

Behavior Scenarios

A. Terminal Execution

.\script.ps1
  • ✅ Progress display visible in the console.
  • Step X complete messages display normally.

B. Redirect to File

.\script.ps1 > output.txt
  • ❌ Progress bar absent.
  • ✅ Only Step X complete messages appear in output.txt.

C. Pipeline Capture

.\script.ps1 | Tee-Object -FilePath output.txt
  • ❌ No progress bar captured.
  • ✅ Text lines are written to both terminal and file.

This test shows that Write-Progress messages are only for seeing things. They are not data that goes into the PowerShell pipeline.


Common Misconceptions Among Developers

Many PowerShell users think you can redirect anything shown in the terminal. This is true for older command-line tools, like bash or cmd. But it is not true for PowerShell.

Misunderstood Assumptions

  • ❌ "Write-Progress works like Write-Output"
  • ❌ "Progress messages flow through stdout"
  • ❌ "Redirection captures all visible console content"
  • ❌ "All IDEs handle host output the same way"

Actually, you can only redirect content from standard streams. Progress visuals work in a different way.

For example, using Visual Studio Code can make this more confusing. Some hosts there might show progress in a different way, or not at all.


How to Fake or Capture PowerShell Progress Output

Standard Write-Progress visuals do not appear in logs or redirected output. So you will need to fake them. PowerShell has a few ways to do this:

1. Use Write-Verbose Instead

This works well if you run scripts with the -Verbose switch.

$ProgressPreference = 'SilentlyContinue'
Write-Verbose "Processing: 40% complete"

2. Output Custom Progress Messages

Plain text output works well in logs or output files.

for ($i = 1; $i -le 5; $i++) {
    $percent = $i * 20
    Write-Output "[Progress] $percent% complete"
    Start-Sleep -Milliseconds 300
}

Log that to a file:

.\script.ps1 > progress.log

Now progress info is actually retained.

3. Use Write-Information

Structured information stream:

Write-Information "Step completed: $i/5" -InformationAction Continue

4. Build a Text-Based Progress Bar

Example:

for ($i = 1; $i -le 5; $i++) {
    $bar = '#' * $i + '.' * (5 - $i)
    Write-Output "[${bar}] $($i * 20)% complete"
    Start-Sleep -Milliseconds 500
}

This creates something that looks like a progress bar. And you can easily capture it in logs.


When You Should Turn Off Progress Output

In many scripts, you do not need to see visual feedback. It can even be a problem.

Situations to Avoid Write-Progress

  • Continuous Integration (CI/CD) environments
  • Docker containers or headless Linux hosts
  • Scheduled Tasks and background jobs
  • Scripts that require full output logging

In these cases, hide progress with:

$ProgressPreference = 'SilentlyContinue'

Or apply it everywhere:

$PSDefaultParameterValues["*:ProgressPreference"] = "SilentlyContinue"

Faking Logging with Progress History

For long scripts, you might want a record of what happened. Then, it is better to log progress in an organized way.

Log-Friendly Format

for ($i = 1; $i -le 5; $i++) {
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $percent = $i * 20
    Write-Output "[$timestamp] Progress: $percent% complete"
}

When you send this to a file, it works well for logs, alerts, or tracking.


Host UI vs. Pipeline: Why Progress Is Different

The PowerShell host shows things on screen using the PSHostUserInterface. This is how they are set up:

  • Write-Progress$Host.UI.WriteProgress()
  • Write-Output → Sent through stream #1
  • Write-Verbose → Stream #4, only if $VerbosePreference allows

You can look at your host interface capabilities:

$Host.UI.RawUI

Complex cases might involve changing or adding to host interfaces for special display rules. But for most users, it is best to use stream-safe options.


Testing and Fixing Progress Behavior

Here are some ways to check and fix progress display issues:

Add Auxiliary Streams

Write-Progress ...
Write-Verbose "Processing halfway..." -Verbose

Use Transcripts

Start-Transcript -Path "debug-log.txt"
# your script code here...
Stop-Transcript

The transcript will record what the host does. This includes progress visuals that normally do not show up in logs.


PowerShell 7 and Cross-Platform Behavior

In PowerShell Core (version 6 and newer) and PowerShell 7, $ProgressPreference works the same way. But how it looks can be different.

Tips for Cross-Platform Scripting

  • macOS and Linux terminals might not show interactive progress at all.
  • Use organized logging (output, verbose, or information streams) for full compatibility.
  • Use if/then logic to decide if showing progress is a good idea.

Example:

if ($IsWindows -and $Host.Name -like "*ConsoleHost*") {
    Write-Progress ...
}

Best Practices for Capturing Progress in a Script

To make your scripts easy to move and predict:

✅ Use $ProgressPreference = 'SilentlyContinue' in automation
✅ Fall back to Write-Output for human-readable progress messages
✅ Avoid relying solely on Write-Progress for data visibility
✅ Test in all expected hosts: terminal, CI pipeline, IDE, etc.


Take Control of Your PowerShell Progress Output

PowerShell's stream model and host design keep visual user interface tasks separate from data processing on purpose. When you understand how this is set up, you can find a good balance. This means balancing how much your scripts interact with users and how much they automate.

Using stream-safe options instead of Write-Progress helps with:

  • Better logging
  • More consistent behavior across different systems
  • Clearer information for fixing issues or for other team members

You might be making scripts for DevOps automation. Or you might be creating complex user processes. Either way, being smarter about progress output helps your PowerShell code. It makes sure the results are right, easy to read, and easy to keep up. This is true no matter where or how you run it.


Citations

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading