2008 Winter Scripting Games

Ben Pearce's Solution to Advanced Windows PowerShell Event 2: Skating on Thin Ice

Event 2 Solution

About the Author

Ben Pearce is a Premier Field Engineer at Microsoft. What does that mean?!? Well, Ben delivers health checks, advises on best practices and develops and delivers workshops, all based on his team’s experiences in the field. Primarily Ben focuses on PowerShell, High Availability and Virtualisation technologies and has worked with many enterprise customers in all of these areas. Ben has been running PowerShell workshops since PowerShell launched, and has traveled throughout the world giving customers the skills they need to craft their own PowerShell scripts. Ben is also the author of the popular blog Ben Pearce’s Guide to Stuff.

*

Skating on Thin Ice


How did I solve this problem? Well contrary to my initial reaction when I first received the task, it wasn’t actually that hard There were a few techniques I hadn’t used for ages, so I did have to do some research, but once I had an understanding of them the solution didn’t take too long.

Firstly, I knew I had to store a skater name, and an associated average score in some kind of data structure. Straight away that sounded like a hash table to me, but I really couldn’t remember the syntax to create and populate one. So, a quick search on www.Live.com and I got taken to this page http://www.microsoft.com/technet/scriptcenter/resources/pstips/sept07/pstip0914.mspx. Those people at the scripting centre to the rescue again. Everything I needed to know about hash tables.

The other reasonably tricky part was to create the string parsing functions. Again, I couldn’t remember all string parsing functions so I used this line

“hello” | Get-Member

This creates a string object, then forwards it to Get-Member which gives me all properties and methods. A quick search of these and a few tests proved pretty useful. I actually did some of these tests interactively in the shell. For example:

PS:> $test = “Ken Myer,55,66,76,67,59,70,54”
PS:> $test.split(",")
Ken Myer
55
66
76
67
59
70
54

Once I had identified the key techniques I needed, I just created a few functions that would parse the string and get the values I needed. I therefore created GetName and GetScores which both take a line of text as input, and return the Name and Score respectively. I needed one more function, GetAverageScore, that I could use to discard the best and worst score, then get the average of the 5 middle scores. Dumping the biggest and smallest score was really easy using the Sort and Select cmdlets, then simple math got me the average.

Once I had created these reusable functions, I needed to read in the text file and iterate through each line. With each line I needed to parse it, get the name and average score, then dump the results to a hash table. I used my old friends Get-Content and ForEach to do this, coupled with the functions I had already created.Once I had read in the file, averaged the scores and dumped them to the hash table I sorted the hash table into descending order using Sort. Once the hash table was sorted position [0] contained the winner, position [1] held silver and position [2] was bronze.

In conclusion, when I first thought about the problem I was a little bit scared. But by breaking the task into small achievable chunks and gluing them together with some simple code the solution wasn’t actually too difficult.

Here’s the final script:

# Event 2 - Skating on Thin Ice 
# Written By Ben Pearce 7th February 2008
# http://blogs.technet.com/benp

# When I started writing this script I forgot the syntax for Hash Tables
# Script Center to the rescue (again)!!
# http://www.microsoft.com/technet/scriptcenter/resources/pstips/sept07/pstip0914.mspx

# Functions ---------------------------------------------------

function GetAverageScore ($Scores)
# This function takes an array of 7 scores, discards the biggest 
# and smallest score, then return the avergage.
{
#Drop the smallest score
$Scores = $Scores | sort -desc | select -first 6
#Drop the biggest score
$Scores = $Scores | sort | select -first 5
$Total = 0
#Sum the remaining 5
foreach ($Score in $Scores)
{
$Total = $Total + $Score
}
#return the average
return ($Total / 5)
}

function GetName ($string)
# This function returns the name of the contestant
{
#Create an array using , to split it up
$StringArray = $string.split(",")
#The first position holds the names
return $stringArray[0].Trim()
}

function GetScores ($string)
# This function returns an array of 7 scores
{
$StringArray = $string.split(",")
#Drop the name and just return the scores
return $stringArray | select -Last 7
}

# ------------------------------------- End Functions

# Start Starts Here!!!!
$filename = "C:\scripts\skaters.txt"
#Read in the file
$file = get-content $filename
#Use a hash table to hold the results.  Create an empty one to begin with
$Results = @{}
foreach($line in $file)
{
$Name = GetName $line
$Scores = GetScores $line
$Average = GetAverageScore $Scores
$Results.Add($Name,$Average)
}

#Sort the results hash table
$results = $results.GetEnumerator() | sort value -Descending

#Output the medal winners
write-host "Gold Medal:" $results.Get(0).Name $results.Get(0).Value -ForegroundColor Yellow -BackgroundColor Black
write-host "Silver Medal:" $results.Get(1).Name $results.Get(1).Value -ForegroundColor Gray -BackgroundColor Black
write-host "Bronze Medal:" $results.Get(2).Name $results.Get(2).Value -ForegroundColor DarkYellow -BackgroundColor Black

When you run this script you should get back the following:

Event 2 Solution
Top of pageTop of page