Page 1 of 1
Stop visible countdown from constantly scrolling its content to bottom of PowerShell window
Posted: 21 Aug 2023 04:02
by DOSadnie
This OK working test script
Code: Select all
Write-Host "Line of text at the very top"
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host "Line of text in the middle"
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host
Write-Host "Last line of text"
Write-Host "Executing in:"
Write-Host
# Countdown:
$topRow = [System.Console]::CursorTop
10..0 | ForEach-Object {
[System.Console]::SetCursorPosition(0, $topRow)
if ($_ -eq 10) {
Write-Host $_ -NoNewline
} else {
Write-Host " $_" -NoNewline
}
Start-Sleep -Seconds 1
Write-Host " `b" -NoNewline
}
# Here will be the main script
Write-Host
Write-Host "Script has been executed"
# Wait for specific user input (ESC, ENTER, or SPACE) before closing the window:
Write-Host "To close this window press either:
Enter
Space
Esc"
Write-Host
do {
$key = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown').Character
} while ($key -notin @(' ', [char]13, [char]27))
stops at a countdown and after it ends proceeds with execution of its remaining part
The problem with it is that every appearing digit makes the PS window scrolls all the way down - thus I can only see for a second what is shown above this active counter. I can constantly scroll up manually but it will always goes back to bottom to show a new digit. I could of course replace this with a silent countdown like
Code: Select all
$CountdownSeconds = 10
Write-Host "Executing in:"
Write-Host $CountdownSeconds
Write-Host "seconds"
Start-Sleep -Seconds $CountdownSeconds
but then I would not be informed anymore about how much time has left
So is there maybe some way to eat a cake and have it - i.e. to see a countdown at the bottom of window but also be able to scroll up and not have the view constantly being scrolled / thrown down?
Re: Stop visible countdown from constantly scrolling its content to bottom of PowerShell window
Posted: 10 Sep 2023 01:28
by DOSadnie
DOSadnie wrote: ↑21 Aug 2023 04:02
[...]
So is there maybe some way to eat a cake and have it - i.e. to see a countdown at the bottom of window but also be able to scroll up and not have the view constantly being scrolled / thrown down?
Any ideas, anyone?
Re: Stop visible countdown from constantly scrolling its content to bottom of PowerShell window
Posted: 12 Sep 2023 09:35
by aGerman
PowerShell is a little off-topic here. However, I had a look at it and found that this behavior is unrelated to PowerShell and happens in Batch as well. It's by design, at least as long as you're running the shell in conhost. Windows Terminal does not override mouse scrolling.
If you really want to work around this effect you need to use the low-level console API. If you look at the man page of these functions, you'll see that Microsoft doesn't want us to use them. The reason is that they are dedicated to conhost and using them along with any other terminal app may cause unexpected results.
It's very easy to import native API functions in PowerShell though. It only requires a type definition in C# code. This may cause a small delay when your script starts because the C# code is compiled to a temporaray DLL first.
Steffen
*.ps1
Code: Select all
# Win32 API wrapper class
Add-Type Console -NS Win32 -MemberDefinition @'
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int id);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern int WriteConsoleOutputCharacter(IntPtr hConOut, string str, int strLen, uint coord, out int written);
//# This function simply writes through to the console screen buffer at the
//# specified coordinates. It does not update the current position of the
//# console cursor.
//# NOTE: The low-level console API is invoked here. Do not use this function
//# in a terminal application other than the classic console (conhost).
//# parameters:
//# x zero-based column index of the writing position
//# y zero-based line index of the writing position
//# text output to be written
//# returns:
//# True if the function succeeds, False otherwise
public static bool WriteAtPosition(uint x, uint y, string text) {
int written;
return 0 != WriteConsoleOutputCharacter(GetStdHandle(-11), text, text.Length, (y << 16) | x, out written);
}
'@
# Just 200 lines of output to scroll the screen buffer.
0 .. 199 | %{ $_ }
# Additional blank line to where the custom function writes (incl. new line
# to where the console cursor jumps).
''
# Always write in the same place, which will result in overwriting the previous
# text. The cursor position is not affected. The screen is not automatically
# scrolled to where the output is updated.
0 .. 50 | %{
if (-not [Win32.Console]::WriteAtPosition(0, 200, "~~~ $_ ~~~")) { 'ERROR' }
Sleep 1
}
Re: Stop visible countdown from constantly scrolling its content to bottom of PowerShell window
Posted: 18 Sep 2023 07:30
by DOSadnie
Thank you; this works as a standalone test PS1 file
But how do I incorporate this into that test script of mine from my initial post?
Re: Stop visible countdown from constantly scrolling its content to bottom of PowerShell window
Posted: 26 Sep 2023 04:36
by DOSadnie
I meant: how do I limit scrolling down to just where the counting takes place? Because your script makes it possible to scroll down through excess of empty lines
I reworked both test into this script
Code: Select all
# Win32 API wrapper class
Add-Type Console -NS Win32 -MemberDefinition @'
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int id);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern int WriteConsoleOutputCharacter(IntPtr hConOut, string str, int strLen, uint coord, out int written);
//# The below function:
//# ● writes through to the console screen buffer at the specified coordinates
//# ● it does not update the current position of the console cursor
//# ● invokes a low-level console API
//# ● mist not be used in a terminal application other than the classic Windows Console [conhost]
//# ● if it succeeds it return True
//# ● if it fails it returns False
//# ● parameters for it are:
//# x ▶ zero-based column index of the writing position
//# y ▶ zero-based line index of the writing position
//# text ▶ output to be written
public static bool WriteAtPosition(uint x, uint y, string text)
{
int written;
return 0 != WriteConsoleOutputCharacter(GetStdHandle(-11), text, text.Length, (y << 16) | x, out written);
}
'@
Write-Host "Line of text - at the very top"
Write-Host
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host
Write-Host "Line of text - in the middle"
Write-Host
Write-Host
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host "Line of text"
Write-Host
Write-Host "Line of text - the last one"
# The countdown - duration and lines below it
$Countdown_Values = 3
# Function to set the buffer height
function SetBufferHeight($height)
{
[System.Console]::BufferHeight = $height
}
# Function to display the countdown without scrolling
function DisplayCountdown($count)
{
$topRow = [System.Console]::CursorTop
$leftColumn = 0
# Set the buffer height to prevent scrolling below the countdown
SetBufferHeight($topRow + $count + 1)
for ($i = $count; $i -ge 0; $i--)
{
if ($i -eq $count)
{
[Win32.Console]::WriteAtPosition($leftColumn, $topRow, "$i") | Out-Null
}
else
{
[Win32.Console]::WriteAtPosition($leftColumn, $topRow, " $i") | Out-Null
}
Start-Sleep -Seconds 1
}
# Restore the original buffer height
SetBufferHeight($Countdown_Values + [System.Console]::WindowHeight + 1)
}
# Display the countdown
Write-Host "Executing in:"
DisplayCountdown $Countdown_Values
Write-Host "Script has been executed"
# Wait for specific user input (ESC, ENTER, or SPACE) before closing the window:
Write-Host "To close this window press either:"
Write-Host "Enter"
Write-Host "Space"
Write-Host "Esc"
Write-Host
do
{
$key = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown').Character
}
while ($key -notin @(' ', [char]13, [char]27))
which does not work correctly - because its issues are:
A] the "Line of text - at the very top" is missing
B] the number that governs the amount of empty lines below the countdown is also the number od seconds for that counter
C] in the end it produces
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text - in the middle
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text
Line of text - the last one
Executing in:
Exception setting "BufferHeight": "The console buffer size must not be less than the current size and position of the
console window, nor greater than or equal to Int16.MaxValue.
Parameter name: height
Actual value was 54."
At C:\q\! SCRIPTS\ZZZ_TEST.ps1:106 char:5
+ [System.Console]::BufferHeight = $height
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Script has been executed
To close this window press either:
Enter
Space
Esc
i.e. it shows an error
Re: Stop visible countdown from constantly scrolling its content to bottom of PowerShell window
Posted: 13 Oct 2023 08:12
by DOSadnie
The Windows Console [conhost.exe] it is supposedly not possible to see digits of a countdown at the bottom of window while also retaining ability to scroll it up an not have the view being thrown back down after passing of another second - but the new Windows Terminal [windowsterminal.exe] however will not snap to the bottom on output if user scrolls up, as it supposedly only snaps to the bottom on output if user is already at the bottom of window when it occurs
Windows Terminal by default replaces the old Windows Terminal since Windows 11 22H2; while installing it on older systems has some prerequisites. Thus it will be easier for me to just wait out this issue
However if anyone can fix the above so-close-to-my-goal script, then please do