Clearing the screen in PowerShell: A story of blank spaces

Microsoft Windows PowerShell is a “task automation framework, consisting of a command-line shell and associated scripting language built on top of, and integrated with the .NET Framework[1]. It basically is a smart replacement for DOS Batch files, resembling the advanced scripting languages of Linux systems, which you can find at Start => All Programs => Accessories => Windows PowerShell.

The reason I am writing this small tutorial is to share a workaround I used in order to prevent empty lines from appearing after clearing the screen. Details follow.

Introduction

In PowerShell, in order to clear the screen you can either type Clear-Host;, its aliases, cls; and clear; or its equivalent [System.Console]::Clear();.

Clear-Host is a PowerShell function, which executes a few lines of code and clears the screen buffer. You can find out what it does by typing ${function:clear-host}; or get-command clear-host | Select-Object -ExpandProperty definition;. The System.Console Clear is a .NET function, commonly used in C# console applications, which PowerShell can also call. Try the commands for yourselves. They work.. kinda.

Identifying the problem

PowerShell has a lot of predefined cmdlets which you can list by typing Get-Command -CommandType Cmdlet;. Some of these cmdlets produce output, depending on how they are programmed to function. Although we do not know exactly how they do what they do, we can make educated guesses based on their results.

So, for example, if you want to print a message onto the screen of the host, you just type Write-Host “Hello World”; and your message immediately appears.

Let’s see another example now. If you want to find what the value of the predefined variable $true is, you can type Get-Variable true; and you will see this output:

As expected, $true = true. Everything looks normal, except for one thing: This built-in cmdlet puts one blank line before its results and two blank lines after. This is not the only thing it does though. If you type the same command twice at the same line, you will see that it also groups up all its results.

The empty lines before and after still appear, but the results are combined because you called the commands together, without returning the control to the shell.

Note that, if you called these commands separately, the results would not get grouped because first the control returns to the shell and then PowerShell continues with the second command.

You cannot change the source code of the built-in cmdlets so you will just have to get used to the predefined addition of the extra line spacing. You can employ certain formatting methods to reorganise the output [2] [3], but I have not found a simple way to remove the empty preceding and succeeding lines.

The actual problem appears, though, when you decide to clear the screen after executing such a cmdlet that adds extra lines below its results.

The un-clearable lines issue

We saw that when you call many semicolon separated commands at the same line, without returning control to the shell, they are considered as a group of commands and behave differently. So this time, let’s try a Get-Variable and a Clear-Host at the same line.

Wait a minute! What are these two blank lines doing above my PS prompt? I just cleared the screen! Two lines.. hmm that number sounds familiar. Oh.

You see, the line-adding output of the cmdlet messed with the current format of the shell and stated that “I want two blank lines after you are done with this group of commands”. Clear-Host was executed inside the command group so, after the screen is cleared, the two separator lines appear and then we return to the shell without a fully cleared screen.

Now.. that is not convenient at all! If you were writing a real script and you wanted to clear the whole screen to provide the feeling of a professional terminal application, having an uncontrollable number of blank lines appearing even after a full clear is not accepted.

A workaround solution

After some research and many experiments, I found out about the “Out-Default[5] and “Out-Host[6] cmdlets. These cmdlets forward the message you send them to the default output or to the host, respectively, which, most of the times, both mean the same thing: the screen.

All the commands you execute in PowerShell sent their output, by design, to the default location but, if you implicitly state so via a pipe then, you can manage to produce a fake “just-returned-to-the-shell” (flush) effect which fully resets the active formatting style, that the cmdlets readjusted, back to the default.

To see this in action, use the aforementioned code but this time pipe (=send/forward) the results of the cmdlet that prints output, either to Out-Default or to Out-Host, like this: Get-Variable true | Out-Default; Clear-Host;

By using this workaround, you may not manage to get rid of the extra lines before and after the cmdlet output, but you succeed in clearing the screen completely, without any extra lines appearing before the shell prompt.

Generalising the findings

You just managed to avoid seeing “ghost lines” before your prompt, right after performing a clear screen. This method can also be applied elsewhere, though.

There is a command called Get-Process which prints the running task list of your system. If you are looking for a specific task, you can type a word contained in its name as a parameter and receive only that line of information. For example, by typing Get-Process idle; you only receive the “Idle” process data.

And now for something which may not be obvious. Each Get- cmdlet has its own default formatting style which it applies to the PowerShell terminal in a first-come-first-served manner, for as long as its command group is executing.

Let me make this clearer to you. Execute a command group in a single line, using two different cmdlets like, for example, a Get-Process and a Get-Variable.

What on earth is going on? I recognise the Get-Process output but why does Get-Variable look like that? Well this happens because both Get-Process and Get-Variable are registered to apply the columned Format-Table formatting [7] but their data are not supposed to get grouped up because they do not have the same number of columns or semantics (=meaning). So, in order to avoid the mix-up, PowerShell lets the first cmdlet apply its formatting to the shell and then force-changes the formatting of the other cmdlets to something else (in this case, Format-List).

If you prefer to see each cmdlet with its default formatting, you have to force every preceding preformatted-output-producing command to stop applying its registered formatting after it has finished running, by piping its output to either Out-Default or Out-Host. By doing this, you flush the output buffer and allow for independent output formatting of any type of grouped commands (e.g. from a single prompt line, a .{dotted curly bracket enclosing} or a .ps1 script file).

This way, the formatting of the terminal will not be permanently affected, thus letting you use the default formatting of each cmdlet, as well as successfully clear the screen every time.

Further reading

If you enjoy coding in PowerShell, have a look at “Learn Windows PowerShell in a Month of Lunches” by Don Jones and Jeffrey Hicks, or start by reading the basics on the guide provided by Microsoft on their website.

References

[1] http://en.wikipedia.org/wiki/Powershell

[2] http://technet.microsoft.com/en-us/library/dd347677.aspx

[3] http://technet.microsoft.com/en-us/library/dd315396.aspx

[5] http://technet.microsoft.com/en-us/library/dd315372.aspx

[6] http://technet.microsoft.com/en-us/library/dd347620.aspx

[7] http://msdn.microsoft.com/en-us/library/bb394649.aspx