Summary: Learn how to display output as moving text by using Windows PowerShell and easy to use techniques.

 

Microsoft Scripting Guy Ed Wilson here. After a long, hot and oppressive summer, Fall has descended upon Charlotte, North Carolina in the United States. The wife (who also scripts) and I decided to head down to the Columbia, South Carolina Riverbanks Zoo. It is an excellent place to spend a cool colorful day. One of the cool things about the Riverbanks Zoo is that they also have an awesome botanical garden. The cool thing about this time of the year is that you might also be able to see a cat playing with a pumpkin—not something one gets to see every day. In fact, as seen in the following image, it seems that this script kitty does not get to play with a pumpkin every day either. He seems completely engrossed.

 

Anyway, because I am on the road and Sean said I needed a day off, I decided to turn the keyboard over to him. Sean Kearney is a Microsoft MVP for Windows PowerShell. He is a network administrator, a Microsoft Certified Technology Specialist in Windows Server Virtualization and Configuration, and a Microsoft Certified Systems Engineer. Sean is a devoted and passionate computer enthusiast from the early 80s to the present day, having used just about every microcomputer ever. Sean taught himself computer programming with 65xxmachine code, working with many technologies―but primarily Microsoft. Sean deals with “anything thrown at him,” from gnawed keyboards to recovery of Exchange servers to networking setups and isolating the realm of the unknown. Currently, he tests and deploys just about any new Microsoft Technology; he also deals with users in an enterprise-class environment. Sean loves Windows PowerShell, Windows 7, and Hyper-V, in that order. You will frequently find him hanging out online at http://www.powershell.ca. Here is his post.

Why do we use computers (or why did we at first)?

I mean as computer nerds, why?

They were fun. Today we are going to do something fun and kinda stupid (but mostly fun).

We will use Windows PowerShell to build a small scrolling marquee - just because, for no other reason.

All we will do is take a line of text or data and make it seem to scroll inside a simple marquee, even if the walls of the marquee are invisible for the moment. 

$TEXT=’ Steve Ballmer is a cool guy with a cool job.’

To make it appear the letters are going across, we will get the position of the cursor from $HOST and keep it on that spot, redrawing the text slightly differently. So part one, remember where the cursor is.

$Position=$HOST.UI.RawUI.CursorPosition

Next we will use the substring() method to draw one letter, then two, then three from the back to the front.

If the line has 44 characters, I draw the 1st and 1 character, the 2nd and two characters, the 3rd and 3 characters so that you get this effect.

S
St
Ste
Stev
Steve
Steve
Steve B

Overlaying this onto one spot will make it appear as if they are “scrolling” to the naked eye. 

To make this occur I will set the CursorPosition back to where I started every single time by using this command:

$HOST.UI.RawUI.CursorPosition=$Position

(Remember? We saved that before we started?)

Now I have to make this into a loop. I will have to repeat this for as many characters as are provided. I can grab this from the .Length from the variable $TEXT.

$Length=$TEXT.length

To simulate a real marquee, I am going to go from left to right. (You can play later and make it do what you want. This is my marquee, nyeah nyeah!)

To achieve this, I am going to use the PadLeft() method to complete the blank space not shown in the word to make my lines seem to come in from the left. To know how many spaces to pad, I just take the length of the string and subtract whatever position I’m on. So, you will get this pattern:

44 Characters total in my string

43 Spaces on the Left – 1 Letter on the right
42 Spaces on the Left – 2 Letters on the right
41 Spaces on the Left – 3 Letters on the right
40 Spaces on the Left – 4 Letters on the right

The pattern is the number of characters - the position equals the number of spaces to pad to the left.

That would produce a loop such as this for a basic marquee.

$TEXT=’This is just something I am going to display’
$Position=$HOST.UI.RawUI.CursorPosition
$Length=$TEXT.length

Foreach ($count in 1 .. $Length) {
     $HOST.UI.RawUI.CursorPosition=$Position
     $text.Substring(0,$count).padleft($Length,' ')
}

 

Now there are two problems. One, the text scrolled too fast and two, on a real Marquee it would disappear. So we have to have a second loop to make it go away. The count of the letters will not change but we will be doing the reverse, displaying fewer instead of more every time, and working our way toward the end, too.  Perhaps we’ll put in a START-SLEEP to slow it down somewhat.

For those of you running Windows PowerShell on a Commodore 64, you negate the need for a START-SLEEP. :)

With our line of 44 characters our current process is somewhat different. We will display characters as follows:

Steve Ballmer is a cool guy with a cool job.
teve Ballmer is a cool guy with a cool job.
eve Ballmer is a cool guy with a cool job.
ve Ballmer is a cool guy with a cool job.
e Ballmer is a cool guy with a cool job.

 

See the pattern? A substring() starting with the following pattern:

Position 0 – 44 Characters Shown
Position 1 – 43 Characters Shown
Position 2 – 42 Characters Shown
Position 3 – 41 Characters Shown
Position 4 – 40 Characters Shown

 

In addition to all this, I have now put in something to keep track of the position in the substring. Fortunately, the position is relative to the Length of the String vs. the Counter position.

$Characters=$Length-$Counter

I can call up and Show the $TEXT, show those characters, and use a Padright like this:

$TEXT.substring($Characters,$Count).padright($length,’ ‘)

A loop that will do all this will look like the following:

Foreach ($count in 0 ..$Length) {
     $characters=$length-$count
     $HOST.UI.RawUI.CursorPosition=$Position
     $text.Substring($characters,$count).padRight($Length,' ')
}

 

Wait a minute. Didn’t I say, “I hate to rewrite code that’s similar?”

Yes, I did. I guess this means I do not get to take the easy way out do I? Drat. Curses.

This is not hard. First, define the stuff we are using all the time, even if it is zero sometimes.

$START=1
$END=$Length
$ZeroCharacters=0

 

Then create a second loop where we “flip” the positions at the end.

$START=($Length+1)-$START
$END=$Length-$END
$ZeroCharacters=1-$ZeroCharacters

Now comes the tricky part. I’m going to make sure when I want to do the first loop, the first part of substring(0,$count) is always 0. When I do the second loop, it will always have the $characters count. Some multiplication will fix that!

$TEXT.Substring(($zerocharacters*$characters),$count)

Then we have those pesky padleft() and padright() methods. Well, that can easily be resolved by using a little boolean and mathematical trickery and an already existing variable we are using for the $characters.

.padleft(([int]!$zerocharacters*$Length),' ').padright(($zerocharacters*$Length),' ')

What that nightmarish statement is really doing is giving us a value of (1 x Length) on the Padleft() method only when $ZeroCharacters is making a Zero Value and the reverse for PadRight() when it is the opposite.

*ACK* *UGH!!* *FAINT!!!*

So boys and girls, sneak in some START-SLEEP –milliseconds 50 for some flavor and we RELEASE THE KRAKEN!

function global:start-marquee ($text) {

# Clear the console of rubbish
CLEAR-HOST

# Are how much information the user keyed in
$length=$text.Length

# Mark our Start end End points for our Marquee loop
$Start=1
$End=$Length
$zerocharacters=0

# Get the position of the Cursor on the screen and move it
$Position=$HOST.UI.RawUI.CursorPosition
$Position.X=4
$Position.Y=5

# Do this over and repeatedly and over ….
    do {
        foreach ($count in $start .. $end) {

        # Keep everthing on the same line
        $HOST.UI.RawUI.CursorPosition=$Position

        # Remember how many characters for that OTHER loop
        $characters=($length - $count)

        # Put exactly WHAT we what WHERE we want WHEN we want
        $text.Substring(($zerocharacters*$characters),$count).padleft(([int]!$zerocharacters*$Length),' ').padright(($zerocharacters*$Length),' ')

        # Time a quick ‘POWER Nap’ – Oh sorry, was that Bad?
        start-sleep -milliseconds 50
        }
        # Flip the counters around
        $start=($length+1)-$start
        $end=$length-$end
        $zerocharacters=1-$zerocharacters
    } Until ($start -eq -9) # You can change this to wait for a key if you REAAALY want :)
}

As seen in the following figure, the text now scrolls.

A static screenshot does not really show the picture. I have uploaded a video demonstration of the script in action. Check it out. There you have it - silly, but fun. Thus confirming two key facts; Windows PowerShell is both fun and useful, and Sean really needs to find more to do with his spare time.

Thanks again to Sean for sharing his script and knowledge with us. Don't forget to join us tomorrow for Weekend Scripter.

We invite you to follow us on Twitter or Facebook. If you have any questions, send email to us at scripter@microsoft.com or post them on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys