September 22nd, 2013

Weekend Scripter: Using PowerShell to Cook Popcorn for Music

Doctor Scripto
Scripter

Summary: Leverage Windows PowerShell for some simple on-screen animation.

Honorary Scripting Guy, Sean Kearney, here. I’m filling in for our good friend, Ed Wilson. Ed got hungry today and asked me to make him some popcorn. So today we’ll use Windows PowerShell to make some—just some little bits for fun.

In actual reality I’m going to have Windows PowerShell generate some simple animations on the screen. This is for fun. Nothing else. After all, it’s the weekend. That’s my excuse!

So first we’ll define an array of the characters that will participate in our little animated fun:

[Array]$Popcorn=$NULL

$Popcorn+=”( 0 )”

$Popcorn+=” ( ) “

$Popcorn+=” O “

$Popcorn+=” o “

$Popcorn+=” * “

$Popcorn+=” | “

$Popcorn+=” \ “

$Popcorn+=” – “

$Popcorn+=” . “

$Popcorn+=” . ” 

If you’re feeling particularly creative and have too much time on your hands like I do, feel free to tweak or expand to this list.

We’re going to have a simple animation occur to show our piece of popcorn moving up the screen. If you remember, last week we used the $Host variable to move the position of the cursor on the screen.

Today we’ll have our piece of popcorn rise up the screen in random positions. That should be fairly easy. We’ll pick a random position to place our “kernel.” To determine where we can “pop” on the screen, we’ll use a little simple logic.

Our column can be anywhere from the left to the right side of the console. Well almost. We have to ensure that we don’t go too far to the left or right.

We’re going to pop in an upwards direction, so we’ll have to make sure that we start as low on the screen as we have elements within our array.

This is all fine and dandy, but wouldn’t it make sense to know just how big the Windows PowerShell window is? We can use the $Host variable. Under RawUI, there is a property called WindowSize, which contains the width and height of our Windows PowerShell window.

Image of command output

When we know this information, we can use Get-Random to accurately place the piece of popcorn. We can use the Width to determine our maximum column position and the Height to figure out just how low we can go (I sense a limbo):

$MaximumX=$Host.UI.RawUI.WindowSize.Width

$MaximumY=$Host.UI.RawUI.WindowSize.Height

Now for the row, we’re going to have to take into account the amount of array elements. So we’ll subtract the total values contained within the array:

$StartColumn=([int](($popcorn[0].Length/2)+.1)

$MaximumX=$Host.UI.RawUI.WindowSize.Width-$StartColumn

$TotalPopcorn=$Popcorn.Count

$MaximumY=$Host.UI.RawUI.WindowSize.Height-$TotalPopcorn 

Now we’ll just use a simple Get-Random for our starting position:

$StartX=$StartColumn=GET-RANDOM $MaximumX

$StartY=(GET-RANDOM $MaximumY)+$TotalPopcorn

Before we get going, we’ll have to obtain the location of the cursor so that we can manipulate it:

$Location=$Host.UI.RawUI.CursorPosition

Now to draw our bits (or technically, bytes) on the screen. For this, we’ll execute a simple loop to start from the bottom of the array to the top:

For ($p=$TotalPopcorn-1;$p –; $p –ge 0)

{

            $Location.Y=($StartY+$p)

            $Host.UI.RawUI.CursorPosition=$Location

            WRITE-HOST $Popcorn[$p] 

During our loop we’re going to make sure that whatever might have been below the cursor will be erased. So move the cursor precisely down one position and draw a blank.

            $Erase=$Location

            $Erase.Y=($StartY+$p+1)

            $Host.UI.RawUI.CursorPosition=$Erase

            WRITE-HOST ”  “

            start-sleep -milliseconds 10

}

Now if we just randomly looped through all of this, we’d see some basic little animations popping on the screen. But popcorn seems to pop randomly. So we’ll use a simple “flip of the coin” to decide in the parent loop on whether the popcorn will “pop”:

If ((GET-RANDOM 50) –lt 30)

{ ScriptBlock for Popping Corn}

ELSE

{ START-SLEEP –milliseconds 1000 }

 Oh. One more thing for fun (and possibly to annoy our coworkers—a random “POP” sound:

[console]::beep(4000+(GET-RANDOM 4000),100)

So let’s put this all together. I’ll call our loop that draws our $Popcorn on the screen a function called “POP-corn” (Oh come on, I had to…I really just had to):

# PowerShell Popcorn

# Define our array of Kernel pieces

 

[Array]$Popcorn=$NULL

$Popcorn+=”( 0 )”

$Popcorn+=” ( ) “

$Popcorn+=” O “

$Popcorn+=” o “

$Popcorn+=” * “

$Popcorn+=” | “

$Popcorn+=” \ “

$Popcorn+=” – “

$Popcorn+=” . “

$Popcorn+=” . “

 

# Grab the cursor position

$Location=$Host.UI.RawUI.CursorPosition

 

# Get our parameters within the Console

$StartColumn=([int](($popcorn[0].Length/2)+.1)

$MaximumX=$Host.UI.RawUI.WindowSize.Width-$StartColumn

 

$TotalPopcorn=$Popcorn.Count

$MaximumY=$Host.UI.RawUI.WindowSize.Height-$TotalPopcorn

 

#Clear the Screen

CLEAR-HOST

 

# Declare our popping cool function

Function pop-corn()

{

 

#Grab a random position

$StartX=GET-RANDOM $MaximumX

$StartY=(GET-RANDOM $MaximumY)+$TotalPopcorn

 

$Location.X=$StartX

 

For ($p=$TotalPopcorn-1;$p –; $p –ge 0)

            {

                        $Location.Y=($StartY+$p)

 

                        # Move the cursor

                        $Host.UI.RawUI.CursorPosition=$Location

 

                        # Drop a Kernel

                        WRITE-HOST $Popcorn[$p]

 

                        # Move the cursor

                        $Erase=$Location

                        $Erase.Y=($StartY+$p+1)

 

                        # Krush an older Kernel

 

                        $Host.UI.RawUI.CursorPosition=$Erase

                        WRITE-HOST ”  “

 

                        # Grab a quick nap

start-sleep -milliseconds 10

            }

}

 

# Let’s decorate the console

$Host.Ui.RawUI.WindowTitle=”PowerShell Popcorn”

 

do {

            # You can adjust the 30 Higher or Lower

            # to increase or decrease the possibility of

            # popping

            if ((GET-RANDOM 50) -lt 30)

                        {

                        # irritate your coworkers with noise

                        [console]::beep(4000+(GET-RANDOM 4000),100)

 

                        # Pop some Corn

                        Pop-Corn                      }

            ELSE

                        # 1000 milliseconds equals one second.

                        # You could make this larger or smaller or even sleep

                        # RANDOM amount of time using

                        #

                        # START-SLEEP –milliseconds (GET-RANDOM 5000)

{ START-SLEEP -milliseconds 1000 }

            }

until ($FALSE)

 Save this as popcornscreen.ps1, run it, and watch the pieces appear all over the screen.

OK, no much silliness in console land. Back to work and more cool Windows PowerShell fun tomorrow!

Does anyone have some butter? I’m getting hungry.

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

Sean Kearney,
Honorary Scripting Guy and Windows PowerShell MVP

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.