Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
July 18, 2024

Verbose Message ANSI Alternatives

If you've been following my work for a while, you know I am a big fan of using `Write-Verbose`. I find the verbose output very helpful when I am writing a PowerShell function. The verbose output writes to a separate stream and is identifiable in the console.

VERBOSE: [14:17:41.9281665 BEGIN  ] Running under PowerShell version 7.4.3
Lately, I've been experimenting with alternatives. Instead of verbose output that is intermingled with the output and that scrolls with the output, I'd like to have a message that is displayed in a specific area, with each message overwriting the previous one. I don't always care about the verbose output after the command finishes. Maybe I only need to see the messages while the code is executing. One way I can accomplish this is by leveraging ANSI escape sequences. You are probably familiar with them from `$PSStyle` to add foreground and background color or styles. But there are also escape sequences that allow you to move the cursor around the console window. You can find this documented on [Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code). - `ESC[nA` Moves the cursor up by n lines - `ESC[nB` Moves the cursor down by n lines - `ESC[nC` Moves the cursor right by n characters - `ESC[nD` Moves the cursor left by n characters - `ESC[2K` Clears the line - `ESC[2J` Clears the screen The `ESC` character in PowerShell 7 is `` `e`` or you can use `[char]27`.
"$([char]27)[2J"
> *The letters in the escape sequence like `A` or `J` are case-sensitive.* For my demonstrations, I am using PowerShell 7 running in Windows Terminal. I expect most of you are using Windows Terminal. This app automatically enables ANSI support. If you are using a different console and not getting the results you expect, you might need to configure output encoding.
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
Here's a simple example of what I want to achieve. You can copy and paste this code into a PowerShell 7 session.
1..10 | ForEach-Object {

    Write-Host "`e[2KWriting message $_"

    Start-Sleep -Seconds 1

    Write-Host "`e[1A" -NoNewline

} -End { "`e[2K" }
You'll see the message 'Write message 1` to `Write message 10` displayed on the same line, overwriting the previous message. When the loop finishes, the line is cleared. You need to be careful about using `NoNewLine` or even if you are using `Write-Host`. Consider this list of names.
$Names = "Alice","Bob","Charlie","David","Eve"
I might try code like this to stream the names to the console, sharing the same line.
$Names | Foreach-Object { "`e[1A$($_)"; Start-Sleep -Seconds 1 }
If you try this, and I hope you do, you'll see the name written in front of your prompt. That won't work. You might try this which first writes an empty line.
$Names | ForEach-Object -Begin { ' ' } -Process { "`e[1A$($_)"; Start-Sleep -Seconds 1 }
Now all of the names are written on the same line, overwriting the previous name. However, if the previous name was longer than the current name, you'll see leftover characters. Let's fix this with ANSI escape sequences.
$Names | ForEach-Object -Begin { "`e[1B" } -Process { "`e[1A`e[2K$($_)"; Start-Sleep -Seconds 1 } -End {

    "`e[1A`e[2K"

}
Much better. This is the kind of thing I have in mind for my code.
$Names | ForEach-Object -Begin { "`e[1B" } -Process { "`e[1A`e[2K`e[93;1;3mSTATUS: Processing $($_)`e[0m"; Start-Sleep -Seconds 1 } -End {

    "`e[1A`e[2K"

}
Status line prototype
figure 1
Figuring out a prototype gave me experience and a better understanding of how to use ANSI escape sequences. Let's apply these principles to some PowerShell code.
Get a premium subscription for full article and archive access

If you've been following my work for a while, you know I am a big fan of using Write-Verbose. I find the verbose output very helpful when I am writing a PowerShell function. The verbose output writes to a separate stream and is identifiable in the console.

VERBOSE: [14:17:41.9281665 BEGIN  ] Running under PowerShell version 7.4.3

Lately, I've been experimenting with alternatives. Instead of verbose output that is intermingled with the output and that scrolls with the output, I'd like to have a message that is displayed in a specific area, with each message overwriting the previous one. I don't always care about the verbose output after the command finishes. Maybe I only need to see the messages while the code is executing.

Want to read the full issue?
GitHub Bluesky LinkedIn About Jeff
Powered by Buttondown, the easiest way to start and grow your newsletter.