---
title: "Write-Progress: Display Progress Bars in Console"
description: "Explore PowerShell Write-Progress, a cmdlet for displaying graphical progress bars and status messages in the console."
canonical: "https://adamtheautomator.com/write-progress/"
---

# Write-Progress: Display Progress Bars in Console

> Explore PowerShell Write-Progress, a cmdlet for displaying graphical progress bars and status messages in the console.

Source: https://adamtheautomator.com/write-progress/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![Write-Progress: Display Progress Bars in Console](https://adamtheautomator.com/wp-content/uploads/2019/06/5d238ae5c824b514689ea545.jpg)

# Write-Progress: Display Progress Bars in Console

[![](https://secure.gravatar.com/avatar/d0b9d42e21e5622713f8b693aa5c0f9244d5f7dd200ed29b8398f52dee5de337?s=192&d=mm&r=g)Adam Bertram](https://adamtheautomator.com/author/adam-bertram/)18 June 20193 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[PowerShell](/tag/powershell/)

Table of Contents

*   [How to Use the Write-Progress Cmdlet](#how-to-use-the-write-progress-cmdlet)

This article will discuss how to use Powershell Write-Progress. Most of the time I prefer to display the working status of my script using `Write-Verbose`. `Write-Verbose` is an excellent way to send periodic messages out to the console to let the user know what’s going on. It’s also nice because you can quickly switch it on and off with the built-in `Verbose` switch.

![Using the PowerShellVerbose parameter](https://adamtheautomator.com/content/images/2019/07/building-progress-bar-powershell-scripts---write-progress.png)

Using the PowerShell`Verbose` parameter

However, `Write-Verbose` is pretty simplistic. It’s just a periodic text display to the console. There’s not much else to it. There are times when you need something more pronounced and a better way to indicate to the script user just how far along in the process your script is. For this, I use the Write-Progress [`Write-Progress`](https://technet.microsoft.com/en-us/library/hh849902.aspx?f=255&MSPPError=-2147217396) cmdlet.

This Powershell cmdlet is ideal for displaying a graphical progress bar right in the console. It’s an intuitive way to not only display status messages to the user but also to have a progress bar to indicate to the user how far the script is along in its execution.

![Write-Progress output](https://adamtheautomator.com/content/images/2019/07/building-progress-bar-powershell-scripts---write-progress2.png)

`Write-Progress` output

## How to Use the Write-Progress Cmdlet

Using this cmdlet is pretty straightforward. At its most basic, you simply need to specify the title of the progress bar using the `Activity` parameter, the status message to display using the `Status` parameter and how much to fill in the progress bar using the `PercentComplete` parameter.

```powershell
Write-Progress -Activity 'Title' -Status 'Doing something' -PercentComplete 0
```

Newcomers to [PowerShell](https://adamtheautomator.com/tag/powershell/) may see this and immediately try to do this something like this:

```powershell
Write-Progress -Activity 'Title' -Status 'Doing something 2' -PercentComplete 25

## Some process here

Write-Progress -Activity 'Title' -Status 'Doing something 3' -PercentComplete 50

## Some process here

Write-Progress -Activity 'Title' -Status 'Doing something 4' -PercentComplete 75

## Some process here
```

At first glance, you might not notice a problem here but think about how this is maintained. Notice the `PercentComplete` parameter. Notice that I had to statically assign the values 0,25,50 and 75? We never want to statically code anything unless necessary. Also, I’m not following the DRY principle here by repeating the same string `Write-Progress -Activity 'Title' -Status 'Doing something'` four different times. We need to refactor this code to come up with a more dynamic way to specify the `PercentComplete` parameter and remove as much code duplication as possible.

To do this, I’ll first need to figure out a way to prevent having to hard code the `PercentComplete` value in each `Write-Progress` call. To do this, I first need to find out how many `Write-Progress` calls I have. Once I figure this out, I can then do some arithmetic to get the actual percentage values.

I can either do this manually or not. I choose not. However, it gets a little hairy at this point. I’ll need to use the PowerShell parser to find each reference to `Write-Progress` just inside of the function itself.

```powershell
$steps = ([System.Management.Automation.PsParser]::Tokenize((gc "$PSScriptRoot\$($MyInvocation.MyCommand.Name)"), [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-Progress' }).Count
```

It now doesn’t matter if I add or remove `Write-Progress` function calls. `$steps` will always have the total number of `Write-Progress` calls in the function.

We can now dynamically pass a value to `PercentComplete` by incrementing a `$stepcounter` variable and creating a percentage value from it.

```powershell
$steps = ([System.Management.Automation.PsParser]::Tokenize($MyInvocation.MyCommand.Definition, [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-Progress' }).Count

$stepCounter = 0

Write-Progress -Activity 'Title' -Status 'Doing something' -PercentComplete ((($stepCounter++) / $steps) * 100)

## Some process here

Write-Progress -Activity 'Title' -Status 'Doing something' -PercentComplete ((($stepCounter++) / $steps) * 100)

## Some process here

Write-Progress -Activity 'Title' -Status 'Doing something' -PercentComplete ((($stepCounter++) / $steps) * 100)

## Some process here
```

Great! But this still looks ugly. Look at all that code duplication! It’s time to build a helper function. I’ll build one now.

```powershell
function Write-ProgressHelper {
    param(
        [int]$StepNumber,
        [string]$Message
    )
    
    Write-Progress -Activity 'Title' -Status $Message -PercentComplete (($StepNumber / $steps) * 100)
}
```

Now, we can simply call this helper function from within the function itself.

```powershell
$stepCounter = 0

Write-ProgressHelper -Message 'Doing something' -StepNumber ($stepCounter++)

## Some process here

Write-ProgressHelper -Message 'Doing something2' -StepNumber ($stepCounter++)

## Some process here

Write-ProgressHelper -Message 'Doing something3' -StepNumber ($stepCounter++)

## Some process here
```

Even though we’ve still got some code duplication, we were able to remove some of it. Since we replaced those `Write-Progress` references to `Write-ProgressHelper`, we’ll have to change the code to find the steps since our steps code was looking for function reference names.

```powershell
$steps = ([System.Management.Automation.PsParser]::Tokenize((gc "$PSScriptRoot\$($MyInvocation.MyCommand.Name)"), [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper' }).Count
```

This finally leaves us with this script.

```powershell
function Write-ProgressHelper {
	param (
	    [int]$StepNumber,
	    [string]$Message
	)

	Write-Progress -Activity 'Title' -Status $Message -PercentComplete (($StepNumber / $steps) * 100)
}

$script:steps = ([System.Management.Automation.PsParser]::Tokenize((gc "$PSScriptRoot\$($MyInvocation.MyCommand.Name)"), [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper' }).Count

$stepCounter = 0

Write-ProgressHelper -Message 'Doing something' -StepNumber ($stepCounter++)
Start-Sleep -Seconds 5

## Some process here

Write-ProgressHelper -Message 'Doing something2' -StepNumber ($stepCounter++)

Start-Sleep -Seconds 5

## Some process here

Write-ProgressHelper -Message 'Doing something3' -StepNumber ($stepCounter++)

Start-Sleep -Seconds 5

## Some process here
```

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fwrite-progress%2F&text=Write-Progress%3A%20Display%20Progress%20Bars%20in%20Console)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fwrite-progress%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fwrite-progress%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/publisher/3f95d9c85b2b81e69730da4c690758c2/4afeea42b7f854d23285b281664351779f042510f1e3a1d766d02cfa39b711a8.jpg)

### [Find and Disable Every Inactive AD Computer with PowerShell](/find-inactive-computers-active-directory/)

Find inactive computer accounts in Active Directory with Search-ADAccount, then disable and quarantine them with PowerShell in steps you can undo.

![](https://adamtheautomator.com/wp-content/uploads/publisher/3f95d9c85b2b814eba23fbf8d18b64a2/ade916ad78256face2456a10aacfbb82051f4957bf03d6f163193b25395e5183.jpg)

### [Back Up and Restore Every Group Policy Object in PowerShell](/backup-restore-gpos-powershell/)

Back up every Group Policy Object with Backup-GPO, restore one or all with Restore-GPO, and recover a deleted GPO with Import-GPO and New-GPLink.

![](https://adamtheautomator.com/wp-content/uploads/publisher/3f95d9c85b2b8181be1be294c37c6724/0ba6a36aaba4a30390fca48d395a19d38846d030302d345372b68b077c3a5cdc.jpg)

### [Find Stuck DFS Replication Backlogs with PowerShell](/dfs-replication-backlog-powershell/)

Find out whether DFS Replication is caught up. Get-DfsrBacklog reads the full file count past the 100-file limit, then a loop checks every group.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
