Hey, Scripting Guy! How About a Formal Wrap-Up of the 2009 Summer Scripting Games?

Hey, Scripting Guy! Question

Hey Scripting Guy! Whatever happened to the Summer Scripting Games? There was all the build up to the games, and then the games were over, and that was it. It would be nice to know what happened. Can you do a recap or something?

— ZQ

Hey, Scripting Guy! Answer

 Hello ZQ,

Microsoft Scripting Guy Ed Wilson here. You know you are right. One of the things that happened is that we are in the middle of a massive migration project that involves manually migrating hundreds of Hey, Scripting Guy! articles from the old platform to the new platform. In addition to all of the Hey, Scripting Guy! articles, there is all the other content (comprising more than 10,000 pages) that needs to be migrated to various places around our new site. Much of that content is being moved to the TechNet Library and some is going to the various technology hubs. In addition to moving the articles, we are also putting in a new Script Repository, which will be called the Script Gallery. This has required us to go back and tag and categorize each of the thousands of scripts we have in the script repository, the community script repository, and the Windows PowerShell script repository. When it is done, we will have a single Script Gallery that will offer some really powerful features such as search and the ability for the community to directly upload scripts.

Because I wanted to show off the features of our new site, I created the Script Center 101 Zunecast to describe some of my favorite things about the new platform. In short, ZQ, we have been swamped. (Not to mention that Craig and I both went on vacation. The Scripting wife and I went to New York City; saw lots of museums, shows, and music events. Nearly caught up with BSonPosh and had a great time. Craig had a great nearcation with his daughter on the Washington and Oregon coasts.)

I had all along wanted to do a Summer Scripting Games wrap-up, or better yet, a Summer Scripting Games greatest hits type of article, but had just let it slip. Now is the time to rectify that situation. Thank you for your kind reminder!

The cool thing about the Scripting Games is they are a great learning opportunity. You may ask how writing a bunch of scripts is a learning opportunity. Suffice it to say that scripting is not a spectator sport and the best way to learn scripting is through the user keyboard interface. Or is it?

This week we will be reviewing some of the scripts that were submitted during the recently held 2009 Summer Scripting Games. The description of the 2009 Summer Scripting Games details all of the events. Each of the events was answered by a globally recognized expert in the field. There were some cool prizes and winners were recognized from around the world. Additionally, just like at the “real Olympics,” because there was a lot going on, an “if you get lost page” was created. Communication with participants was maintained via Twitter, Facebook, and a special forum. The special forum has been taken down, but we still use Twitter and Facebook to communicate with Hey, Scripting Guy! fans. We will be focusing on solutions that used Windows PowerShell. We have several good introduction to Windows PowerShell Hey, Scripting Guy! articles that you will find helpful.

Maybe scripting is a good spectator sport as well, if you analyze the scripts. In addition to the great solutions offered by the expert commentators, we also have hundreds of awesome scripts being stored over at PoshCode. If you are ever stuck for a little late night fun, hop on over there and read through the entries. There are some really good ideas and some well-crafted scripts. You will learn a lot. Today we are going to look at the submission by LKH for Beginner Event 1. If you would like to follow along, you can download the Competitor’s Pack from the Microsoft Download Center. LKH’s complete solution to the 2009 Summer Scripting Games Beginner Event 1 is seen here.

2009 Summer Scripting Games Beginner Event 1

# Beginner Event 01
# AUTHOR  : lkh
# DATE    : 2009-06-20
# NAME    : be01.ps1
$lines = Get-Content ‘100 Meter Event.txt’
1..$($lines.Length-1) | foreach {
    $aMatch = ([regex]'(.+?)t(.+?)s+([d.]+)’).Match($lines[$_])
    $oRunner = New-Object PSObject
    $oRunner | Add-Member NoteProperty Name     $aMatch.Groups[1].Value.Trim()
    $oRunner | Add-Member NoteProperty Country  $aMatch.Groups[2].Value.Trim()
    $oRunner | Add-Member NoteProperty Time     ([double]$aMatch.Groups[3].Value.Trim())
} | Sort-Object Time | Select-Object -First 3

The goal of Beginner Event 1 was to read the text file shown in the following image and determine the first place, second place, and third place winners from a 100-meter race.

Image of the text file for Beginner Event 1

One of the things I like about LKH’s solution is the way they used the Windows PowerShell New-Object cmdlet to create a new PSObject. We will see that in just a little bit.

The first thing that LKH does is use the Get-Content cmdlet to read the contents of the 100 Meter Event.txt file and stores the resulting array of text in a variable named $lines. The default parameter for the Get-Content cmdlet is the path parameter. You will need to make sure that the path points to the location of the text file. This line of code, seen here, is for my computer that has an fso folder off the C: drive. I like to include the parameter names in my scripts, so I have added the path parameter to my line of code.

$lines = Get-Content –path ‘C:datafso100 Meter Event.txt’

After creating the array of text and storing it in the $lines variable, LKH creates an array of numbers that matches the number of lines in the text file. To do this, LKH uses the range operator and then pipes the numbers to the ForEach-Object cmdlet. This gives the ability to work with each individual line from the text file. I like to use complete cmdlet names in my scripts and avoid the use of aliases. Foreach is an alias for the ForEach-Object cmdlet (it is also the Foreach language statement, which makes things much worse):

1..$($lines.Length-1) | Foreach-Object {

The first complicated thing is the use of regular expressions.  A good introduction to using regular expressions from the .NET Framework classes is on MSDN. We also have several Hey, Scripting Guy! articles that detail working with regular expressions on the Script Center.

The first pattern uses the period meta character, which matches a single character. The plus character matches one or more occurrences of a character and the question mark matches zero or more occurrences. Therefore, the pattern “(.+?)” will match one or more characters followed by zero or more characters. You can easily test the regular expression pattern by using this, as seen here:

PS C:> $pattern = “(.+?)”
PS C:> “abc” -match $pattern
PS C:> “a5” -match $pattern
PS C:> “a” -match $pattern
PS C:> “a ” -match $pattern
PS C:> “” -match $pattern

The t is a tab character. When put together with the previous pattern, we have one or more characters followed by zero or more characters followed by a tab and one or more characters followed by zero or more characters. The pattern at this point looks like the following:


You can test the pattern by using the match operator as you did earlier by assigning it to a variable and working interactively inside the Windows PowerShell console. This is seen here:

PS C:> $pattern = “(.+?)t(.+?)”
PS C:> “a string” -match $pattern
PS C:> “a`tstring” -match $pattern
PS C:> “a`tstring”
a       string

The last section of the regular expression pattern uses the s to find any white space, the d to find any decimal digit, and . to find the dot (period) character. The reason for using . is to escape the period, which as we have seen is a special character that represents a single character. To actually look for the period character itself, use a backslash in front of it. The complete pattern is seen here:


Once again, it is a good idea to test the pattern before putting it into the script. This is done here:

PS C:> $pattern = “(.+?)t(.+?)s+([d.]+)”
PS C:> “this`tis a pattern 1.1” -match $pattern
PS C:> “this`tis a pattern ” -match $pattern

The complete line from LKH’s script is seen here:

$aMatch = ([regex]'(.+?)t(.+?)s+([d.]+)’).Match($lines[$_])

The next thing that is done is to create a new object. This object is a PSObject and it is simply an empty object. It does not contain anything until items are added to it. Actually, some methods are automatically added to it, because it is a PSObject. This is seen here:

PS C:> $oRunner = New-Object PSObject
PS C:> $oRunner | Get-Member

   TypeName: System.Management.Automation.PSCustomObject

Name        MemberType Definition
—-        ———- ———-
Equals      Method     System.Boolean Equals(Object obj)
GetHashCode Method     System.Int32 GetHashCode()
GetType     Method     System.Type GetType()
ToString    Method     System.String ToString()

To add properties to the object, you use the Add-Member cmdlet and specify the membertype, the name, and the value of the member you are adding to the object. As stated previously, I prefer to use parameter names in my scripts because it makes the script easier to read. I have added the parameters here:

    $oRunner | Add-Member -membertype NoteProperty -name Name -value $aMatch.Groups[1].Value.Trim()
    $oRunner | Add-Member -membertype NoteProperty -name Country -value $aMatch.Groups[2].Value.Trim()
    $oRunner | Add-Member -membertype NoteProperty -name Time -value ([double]$aMatch.Groups[3].Value.Trim())

The resulting object is piped to the Sort-Object cmdlet and then the first three items are selected. This is seen here:

| Sort-Object Time | Select-Object -First 3

When the script is run, the output seen here is produced:

Image of the output of the script

Well, ZQ, thank you for reminding us to close the loop on the 2009 Summer Scripting Games. Also, we want to wish a special thanks to LKH for writing a really cool solution to the Beginner Event 1, the 100-meter dash. If you want to be the first to know what is happening on the Script Center, follow us on Twitter or Facebook. If you need assistance with a script, you can post questions on the Official Scripting Guys Forum, or send e-mail to scripter@microsoft.com. The 2009 Summer Scripting Games wrap-up will continue tomorrow. Until then, peace.


Ed Wilson and Craig Liebendorfer, Scripting Guys