Tag Archives: Clear-Host

Clear Screen After Every Command

Here we go again. I just rescued another draft post, fixed it up enough to share, and published it. Again, this was one of those posts that just never made it past my drafts for one reason or another. I think I figured out what I wasn’t doing correctly, so I’m ready to hand it off.

Never know when I’m going to get inspired to write. Well, I just did and I’m not even sure how it started. All of sudden, I began thinking about ways in which to mess with someone using PowerShell. Perhaps it’s that April Fool’s Day just passed. It’s actually coming, this post is so overdue. I thought to myself, can I get the ConsoleHost to clear each time something is entered? Yeah, of course I can: the prompt function. Been here, done that, just not with such cruel, and obnoxious intentions.

Now to figure it out, for you (and next April Fool’s Day, perhaps). The idea is not to completely modify the prompt function, so as to tip off the user. Instead, the idea is to get their prompt — customized or not — and stuff a Clear-Host command to the end of it. That’s right, every time they enter a command and the prompt is redrawn, it’ll clear the host. Ha! Let’s do this. Yeah, let’s.

How you’re going to get on to your friend’s computer to do this, is up to you. That’s not what I’m here for, just remember your buddy is going to need to spend at least some time in the PowerShell console. Your click-next admin buddies aren’t going to see (or appreciate) this prompt function.

First, we need to get the content that makes up their prompt. It doesn’t matter if it’s been customized or not. Here’s the full command to do that. This command will assign the prompt’s ScriptBlock property to the $CurrentPrompt variable. Additionally, it will pass the value to the ToString() method.

PS MyPrompt > $CurrentPrompt = (Get-Command -Name prompt).ScriptBlock.ToString()

Let’s take a look at the contents of the $CurrentPrompt variable. If you didn’t notice already, you’ll be able to tell that I started with a custom prompt.

PS MyPrompt > $CurrentPrompt
    'PS MyPrompt > '

Next, we’ll create a $NewPrompt variable. Notice that this code includes the $CurrentPrompt variable we created in the first step. This is how we can ensure the prompt has the same look, whether it’s been customized or not. The difference now, is that we’ve added a Clear-Host command inside there. So mean. And Awesome.

PS MyPrompt > $NewPrompt = "$($CurrentPrompt)Clear-Host"

This final command will overwrite the current prompt function with our modification.

Set-Content -Path Function:\prompt -Value $NewPrompt

In closing, I want to provide the full code I used for testing. This contains four different clean prompts, as well as the code we saw above to make the modifications. The first prompt is the one I use on a daily basis and discussed several times around here — it’s my Linux lookalike prompt. Anyway, this will give you some test code to copy to your system and play with. Have fun, then torture your coworkers, but I didn’t say that.

Function Prompt {
	(Get-PSProvider -PSProvider FileSystem).Home = $env:USERPROFILE

	# Determine if Admin and set Symbol variable.
	If ([bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).Groups -match 'S-1-5-32-544')) {
		$Symbol = '#'
	} Else {
		$Symbol = '$'
	}
	 
	# Write Path to Location Variable as /.../...
	If ($PWD.Path -eq $env:USERPROFILE) {
		$Location = '/~'
	} ElseIf ($PWD.Path -like "*$env:USERPROFILE*") {
		$Location = "/$($PWD.Path -replace ($env:USERPROFILE -replace '\\','\\'),'~' -replace '\\','/')"
	} Else {
		$Location = "$(($PWD.Path -replace '\\','/' -split ':')[-1])"
	}

	# Determine Host for WindowTitle.
	Switch ($Host.Name) {
		'ConsoleHost' {$HostName = 'consolehost'; break}
		'Windows PowerShell ISE Host' {$HostName = 'ise'; break}
        'Visual Studio Code Host' {$HostName = 'vscode'; break}
		default {}
	}

    # Determine PowerShell version.
    $PSVer = "$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)"

	# Create and write Prompt; Write WindowTitle.
    $UserComputer = "$($env:USERNAME.ToLower())@$($env:COMPUTERNAME.ToLower())" 
    $Location = "$((Get-Location).Drive.Name.ToLower())$Location"

    # Check if in the debugger.
    If (Test-Path -Path Variable:/PSDebugContext) {
        $DebugStart = '[DBG]: '
        $DebugEnd = ']'
    }

    # Actual prompt and title.
    $Host.UI.RawUI.WindowTitle = "$HostName $PSver`: $DebugStart[$UserComputer $Location]$DebugEnd$Symbol"
    "$DebugStart[$UserComputer $Location]$DebugEnd$PSVer$Symbol "
}

Function prompt {
    "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "
}

Function prompt {
    'PS > '
}

Function prompt {
    'PS MyPrompt > '
}

Get-ChildItem # Verify no Clear-Host command included.

$CurrentPrompt = (Get-Command -Name prompt).ScriptBlock.ToString()

$CurrentPrompt
	
$NewPrompt = "$($CurrentPrompt)Clear-Host"

Set-Content -Path Function:\prompt -Value $NewPrompt

Get-ChildItem # Verify Clear-Host command included.

Clear-Host, Without Clearing the Host – Part 2 (TMConsole Module)

Download the TMConsole Module here: https://gallery.technet.microsoft.com/TMConsole-Module-Clear-487eff0e

Back in early September, I wrote a post about “clearing” the host. I was proud of my simple, little function, that I then called clx, and so in early October, I linked the post on Twitter. To my surprise, a few well-known names in Windows PowerShell helped promote the blog post. I’m talking about PowerShell MVPs, authors, and community bloggers – the very people I look up to and learn from.

Just recently, I decided it would be wise to add comment-based help and some minor logic-based, error checking to the function, and then post it on the Microsoft TechNet Gallery. In addition, I wanted to combine it with another simple console function that I use, and upload them both as a module.

If you’ve read the link above then you already know about the first half of the module (the Clear-TMConsole function, aka clx). The second half of this module (the New-TMConsole function) simply opens a new PowerShell console and provides the user the option to keep, or close the current console. I wrote this function because there are many times when I want a fresh console that doesn’t have any left over variables. I was tired of typing Start-Process (or saps) powershell. I understand these are simple, but I’ve become quite dependent on them to speed up my work, and to mildly safeguard information I want to keep in my console(s).

Below are a few aliases I use to help speed up my use of the functions. Opening a new console, and closing the current one, is as simple as entering: nc y n and pressing enter. The y is to indicate to continue running the New-TMConsole function, and the n indicates to not keep the current console. Hopefully this module can be helpful to others, too.

Set-Alias -Name nc -Value New-TMConsole
Set-Alias -Name clx -Value Clear-TMConsole
Set-Alias -Name cc -Value Clear-TMConsole

Download the TMConsole Module here: https://gallery.technet.microsoft.com/TMConsole-Module-Clear-487eff0e

Clear-Host, Without Clearing the Host

After you read this, read part 2 (and download the TMModule)

I use the Clear-Host cmdlet alias, cls, throughout the day to clear out whatever typing I have inside my Windows PowerShell console. It does its job well, but recently I’ve wanted it to work differently. I wanted it to appear that the console host has been cleared, but still allow me to scroll back up to see what was on the screen before it was cleared. I started playing around with the console class, [Console]. While not necessary, this can also be written using the namespace, System, such as [System.Console]. I like the idea of being as complete as possible and so you’ll see me use the namespace even though it’s not necessary.

Before I could write something reusable, such as a function, I had to figure out if what I wanted to accomplish, was even possible. I knew I was working with [System.Console] and so I piped that to Get-Member, but it returned the methods and properties of System.RuntimeType, seen below.

PS C:\> [System.Console] | Get-Member

    TypeName: System.RuntimeType

I struggled for a moment until I remembered an article I had read on using static classes. I found that page again, http://technet.microsoft.com/en-us/library/dd347632.aspx, and was quickly reminded that using the -Static parameter of the Get-Member cmdlet would get me the correct results.

PS C:\> [System.Console] | Get-Member -Static

    TypeName: System.Console

Running the command above produces the TypeName as shown, but it also produces all the methods and properties. I started looking over the properties and a couple about the cursor quickly caught my eye, especially the CursorTop property. After the Get-Member command from above, and based on the results of returning the CursorTop property, my cursor was positioned at line 59 inside my console, as can been seen in the example below on line 2. I cleared the screen, and beginning on line 4 below, I reran the command three more times. Each time, it gave me the location where the cursor was last positioned.

PS C:\> [System.Console]::CursorTop
59
PS C:\> cls
PS C:\> [System.Console]::CursorTop
1
PS C:\> [System.Console]::CursorTop
3
PS C:\> [System.Console]::CursorTop
5
PS C:\>

I decided I would assign the value, 0, to the CursorTop property and suddenly I was writing over the text on the top line. Take a close look at line 1 below.

PS C:\> blahblahConsole]::CursorTop
59
PS C:\> cls
PS C:\> [System.Console]::CursorTop
1
PS C:\> [System.Console]::CursorTop
3
PS C:\> [System.Console]::CursorTop
5
PS C:\> [System.Console]::CursorTop = 0

I could move my cursor, great, but this wasn’t exactly what I wanted. What I wanted was to push that scroll bar down so that anything that was already on the screen was pushed off the top of my console, and all that was left was my PowerShell prompt. I still believed there was a way to do this and so I spent a little more time looking over the properties. I found four that began with Window – WindowHeight, WindowLeft, WindowTop, and WindowWidth – and began to experiment with them. I didn’t suspect I’d be doing anything with the height and width but I thought I would check out their values anyway – 50 and 120, respectively.

PS C:\> [System.Console]::WindowHeight
50
PS C:\> [System.Console]::WindowWidth
120
PS C:\>

WindowLeft didn’t seem to be that important, because no matter how much was typed before I entered [System.Console]::WindowLeft, the property value was still set to 0. Then I entered in [System.Console]::WindowTop and it was also 0 every time. Then it dawned on me, what if I changed its value like I did with CursorTop. I tried it and my scroll bar started jumping all over. I’m getting close!

PS C:\> [System.Console]::WindowTop = 10
PS C:\> [System.Console]::WindowTop = 200
PS C:\> [System.Console]::WindowTop = 2000
PS C:\> [System.Console]::WindowTop = 0

We know the CursorTop value changes, so what would happen if we set the value of WindowTop to CursorTop? I tried it, and it worked!

PS C:\> [System.Console]::WindowTop = [System.Console]::CursorTop
PS C:\>

I thought I was done when I took another moment and scanned over the methods. I found one called SetWindowPosition. Instead of simply assigning a new value to the property WindowTop, I decided I would use the method to do the work for me. I eventually ran both of these options through the Measure-Command cmdlet and determined that there was no gain in speed by using one option over the other.

So, once I knew what to do, I opened my profile ($PROFILE) and created an empty function. For whatever reason, I called it clx thinking that this would be a good option for me. Turns out that while clx has little meaning, I was able to quickly remember it and start using it right away. Now, every time I want it to appear that I’ve cleared my host, but didn’t really, I type clx and press Enter.

Function clx {
    [System.Console]::SetWindowPosition(0,[System.Console]::CursorTop)
}

I added one additional feature to this function as is seen in the example below. This option allowed me to run the clx function and leave the last n number of rows on the screen. Try it out by ensuring your have some output in your console and then entering clx 2. This will “clear” the console screen but still allow you to view the last two rows without scrolling back up. Try it and it may make more sense.

Function clx($SaveRows) {
    If ($SaveRows) {
        [System.Console]::SetWindowPosition(0,[System.Console]::CursorTop-($SaveRows+1))
    } Else {
        [System.Console]::SetWindowPosition(0,[System.Console]::CursorTop)
   }
}

Here’s a video of the function in action. The first thing we do is return 5 processes and then 5 services. Then we use cls and notice that we cannot scroll back up to see what was cleared. This is the typical behavior. When we add the processes and services back, and then use the clx function, we can see that we have the option to scroll back up and see what was on the screen, before we “cleared” it.