2014 Winter Scripting Games

The 2014 Winter Scripting Games, beginning in the middle of January, gives you the opportunity to test your Windows PowerShell skills and get feedback from Subject Matter Experts. New this time is the ability to form teams and collaborate on the given challenges, which in practice will simulate a real world scenario where you collaborate with your colleagues.  Each team will need to have at least 2 persons. There will be judges for scoring the events as well as coaches offering comments and advice to the teams. Personally I will be contributing to the games as a coach, which I`m really looking forward to. I will also write articles on my blog giving advice on my observations during the games. If you want to participate, be sure to read the 2014 Winter SG Players Guide.

You can find more information in the following articles over at powershell.org:


Also be sure to check the 2014 Scripting Games category every day during the games in order to stay updated on the latest announcements. Alternatively you can subscribe to the RSS feed.

Of course, you could also fetch the RSS feed using Invoke-WebRequest:

$result = Invoke-WebRequest -Uri http://powershell.org/wp/category/announcements/scripting-games/feed
$result.rss.channel.item | Format-Table title,pubdate,link -AutoSize



For those of you based in Norway I would also be very happy if you would like to join our local MTUG Script Club team for the games, you can find for information here. There will also be a practice event available starting to accept entries on January 6th.

Good luck to everyone and have fun!

2013 Scripting Games – Learning points from Event 6

The 2013 Scripting Games started April 25th, and event 6 is now open for voting. This is the last event, and I must say I have learned a lot by reviewing scripts from all of the events. One of the great things about PowerShell is that there are many ways to perform a task, and by seeing how others solves it is a great learning opportunity. As I did in the previous events, I will pick out two entries from each event and provide some learning points to highlight both good and bad practices.

Before reading my comments, you might want to download the event instructions:

The first entry I will comment on is from Beginner 6:

The #requires statement is used to ensure that version 3.0 of PowerShell is being used when executing the script. This is good since functionality only available in version 3.0 is leveraged, such as the DHCP Server module.

  • The #requires statement could also have been used to ensure that the DHCP Server module is present on the system: #Requires –Modules DhcpServer. This would have saved some code, instead of using an if statement to see if the module is present.
  • The passwords could have been hardcoded, but for security reasons it is a good idea to prompt the user.
  • The event did not specify that the DHCP server is running Windows Server 2012, but I think it is ok to assume that in this event so the DHCP Server module can be leveraged to query the server. A foreach loop with error handling is used to obtain the IP address for each computer.
  • The information obtained from the previous foreach loop is saved to an array ($ipAddrs), which a new foreach statement is looping through in order to add the computers to the domain. Using Add-Computer is ok, but there is a gotcha not everyone thought of: The cmdlet is using WMI (the JoinDomainOrWorkgroup method of the Win32_ComputerSystem class), which is not available by default. Since the new computers is using Windows Server 2012, we can rely on PowerShell Remoting being enabled by default. One approach could then be to use Invoke-Command, and pass the Add-Computer cmdlet to Invoke-Command`s ScriptBlock parameter.

The next submission I will comment on is from Advanced 6:

  • Comment based help is leveraged to provide a synopsis, description, help for all parameters, input/output type information, notes and the link to the event.
  • The #requires statement is used to ensure that the PowerShell version is minimum 3.0, and that the DHCP Server module is available on the system. This is very good.
  • The parameters is well defined. For the OU parameter, input validation is performed within the function. I would rather have leveraged ValidateScript for the validation, which is used for the MacAddress parameter.
  • PowerShell Workflow is leveraged, but all remoting capabilities is not. Instead, the Windows Firewall is disabled in order to use the Restart-Computer cmdlet with its default protocol (DCOM). It is possible to specify WSMan as the protocol for the Restart-Computer cmdlet (-Protocol WSMan). Disabling the firewall is bad in terms of security. Note that if using PowerShell Remoting, we would also need to modify the TrustedHosts list in order to communicate with a workgroup computer. Some entries used * as the value for the TrustedHosts list. A better approach from a security standpoint would be to add the IP address for the computer we are connecting to, and to remove it after the remote commands is executed.

PS: Mike F Robbins has a very good article showing how to use PowerShell Workflow in this event.

Thank you to everyone who participated, I already look forward to the next Scripting Games. For those of you who did not participate this time, using the events as tasks for yourself (or your local PowerShell User Group) is a great learning opportunity.

2013 Scripting Games – Learning points from Event 5

The 2013 Scripting Games started April 25th, and event 5 is now open for voting. As I did in the previous events, I will pick out two entries from each event and provide some learning points to highlight both good and bad practices.

Before reading my comments, you might want to download the event instructions:

The first entry I will comment on is from Beginner 5:

  • Although the event instructions indicated that a one-liner would be sufficient, this is a parameterized script with comment-based help added. Normally this is a very good idea in regards of documenting the script and making it easier to use against other paths. But in this case, Dr. Scripto specifically stated that he is keeping his log-files in a fixed path (C:\Reporting\Logfiles).
  • The PathtoLogs parameter is mandatory. Nothing wrong with that either, but I would have skipped that and added Dr. Scriptos fixed path as a default value for the parameter in regards to the instructions:     [string]$PathtoLogs = “C:\Reporting\Logfiles”
  • A regular expression is used to find IP addresses from the log files. This is a good idea which many participants used. However, this particular regex will also match non-legal IP addresses, such as 999.999.999.999.
  • -AllMatches is added to Select-String so that all matches is returned, not only the first one.
  • Lastly, Select-Object –Unique is used to get the unique IP address.

There were many creative ways of solving this event, and many did so with a one-liner. One alternate way one of the submissions used was a technique found on StackOverflow: Using Import-Csv:

param ($logfile)
import-csv -Delimiter " " -Header "date","time","s-ip","cs-method","cs-uri-stem","cs-uri-query","s-port","cs-username","c-ip","csUser-Agent","sc-status","sc-substatus","sc-win32-status","time-taken" -path $logfile | where { !($_.Date.StartsWith('#')) }

Another interesting approach was using the [ipaddress] type accelerator.

For those using a regular expression, Chris Warwick has written an excellent article on how to validate an IPv4 address using regex. PowerShell is using .NET regular expressions, so you might also want to bookmark a .NET regular expression cheat sheet.

Moving on to a submission from Advanced 5:

  • First of all, this is a very well documented function containing full documentation for all parameters, several examples, information about the functions input and output as well as very detailed information in the notes.
  • ValidateScript is used to validate that the specified folder exists, and to make sure it contains .log files.
  • ValidatePattern is used to provide IP filtering capabilities, if not specified it defaults to *.
  • ValidateRange is used to validate input to the ReadCount parameter. A tested value of 1200 is provided as the default.
  • The last two parameters is switch parameters, providing options to get instance counters per ClientIP, as well as outputting a hash table instead of objects.

Every step in the scriptblock is well documented, and I find it unnecessary to comment any further. This is an excellent submission, which is clearly tested in a production environment. The only thing I would have added is support for sub-folders, by adding a –Recurse switch. Although, this was not specifically required by the event instructions. We can work around that by using Get-ChildItem –Directory to get the sub-folders: Get-ChildItem -Directory -Path “C:\Reporting\LogFiles” | Get-ClientIPFromIISLogs

Now we have only one event left before the 2013 Scripting Games is over. Keep up the good work, and good luck with event 6 – “The Core Configurator”.

2013 Scripting Games – Learning points from Event 4

The 2013 Scripting Games started April 25th, and event 4 is now open for voting. As I did in the previous events, I will pick out two entries from each event and provide some learning points to highlight both good and bad practices.

Before reading my comments, you might want to download the event instructions:

The first entry I will comment on is from Beginner 4:

  • Comment based help is leveraged to provide a synopsis, description and basic usage. Comment-based help and the Active Directory module which is leverage was introduced in PowerShell 2.0, thus #requires –version 2.0 could have been used to prevent users trying to run this in PowerShell 1.0 getting error messages.
  • HTML-formatting (head, pre- and post-content) as well as a couple of other variables is defined (note that I have updated my previous article with more info on working with HTML in PowerShell). I would also suggest the search base to be specified as a variable rather than a hard coded path in the script. Although, this is specifically stated in the synopsis.
  • The time stamp for when the report was created is included in the bottom of the report as required by the event instructions. In addition the username of the user generating the report is added, which is nice.
  • The actual cmdlets generating the report is a one-liner, nicely formatted on multiple lines for readability.
  • The lastlogon date property is used to determine when the users last logged on to the domain. There are ways to retrieve this information, and not all of them is accurate. For example the lastlogontimestamp property will be 9-14 days behind the current date. For more information, see this article on the “Ask the Directory Services Team” blog. To get a more accurate time stamp, you might want to query all domain controller, see this TechNet article for one example on how to accomplish this. Although I would not withdraw any points for not catching this “gotcha”, I would give a bonus point for those who did.


The second entry I have decided to comment on is from Advanced 4:

  • Leveraging the #requires statement is a good practice, however, this should be separated into two lines. When the script is run “as is” in PowerShell 2.0 the following error will be returned: “Cannot process the “#requires” statement at line 1 because it is not in the correct format.”. If separating into two lines, it will work in both 2.0 and 3.0:

#Requires -Version 3.0
#Requires -Module ActiveDirectory

  • Comment based help is leveraged in an excellent way, providing both help for all parameters as well as several examples.
  • [CmdletBinding()] is defined in order to use [Parameter()] decorators to validate input. Although there is nothing wrong with parameterizing this as a script, I would consider to turn it into a function (a personal preference).
  • The FilePath parameter is marked as mandatory, as well as positional. This is perfectly fine, but another option would be to default to a path using an environment variable (for example $env:userprofile\Documents\Report.html). The requirement of validating the filename extension (htm or html) is accomplished using a regular expression inside a ValidateScript validation.
  • The Count parameter is configured with a default value of 20 as required. In addition ValidateRange is leveraged to make sure the number specified is valid. This is not necessary, as defining the parameter as an integer would perform the necessary validation:

Cannot convert value “2222222222222222” to type “System.Int32″. Error: “Value was
either too large or too small for an Int32.

  • Two additional parameters is supplied: One for overwriting the report-file if it exists (-Force) and one returning the newly created HTML file (-PassThru). These two parameters provide additional functionality not required by the instructions.
  • The parameter values for ConvertTo-Html is quite large, and providing these as a hashtable and leveraging splatting makes it more readable. This also makes it possible to collapse/expand the HTML-code (the hashtable) in PowerShell ISE.
  • The PSCustomObject type accelerator is used to create new objects. There are many ways to create new objects in PowerShell 3.0, but this is the easiest/preferred way in my opinion. Also, the new [ordered] type adapter in PowerShell 3.0 is leveraged to decide the order of the properties, rather than using Select-Object which will actually create new objects (more overhead).

Like the previous events, there have been many great submissions in event 4. Keep up the good work, and good luck with event 5 – “The Logfile Labyrinth”.

2013 Scripting Games – Learning points from Event 3

The 2013 Scripting Games started April 25th, and event 3 is now open for voting. As I did in the previous events, I will pick out two entries from each event and provide some learning points to highlight both good and bad practices.

Before reading my comments, you might want to download the event instructions:

The first entry I will comment on is from Beginner 3:

  • Two pieces of information is required for this event, which we typically find in WMI. Since the instructions clearly stated that both CIM and WMI is available, and we do not have to think about authentication or firewalls, I find leveraging CIM a good practice. CIM is the newest technology, based on standards based management. It also requires just one firewall port to be open, compared to WMI which requires a lot more. Although, I would not give less points if WMI was leveraged in this event, since this is also a valid option in the instructions. In the real world however, we would typically need to think about authentication and firewalls in addition to other considerations, such as legacy systems. If Windows 2000 was still present, CIM would not have worked against WMI on that system without specifying the DCOM protocol for the CIM session.
  • Filtering is performed on the server side, which speeds up the query. A bad practice would have been skipping the –Filter parameter, and performed the filtering on the client side using Where-Object.
  • Extracting the data required by the instructions is done using Select-Object. What I also like is that formatting the data is done in the same operation. The –f operator is used to format the data, and PowerShells built-in constants for converting values to MB and GB is leveraged.
  • PowerShell has built-in capabilities to convert objects to HTML, in the form of the ConvertTo-Html cmdlet. This is leveraged in a way that meets the goals for the event instructions: The 3 properties needed is specified, and a header and a footer is added with the required data. However, a bonus point would have been added if the computer name was added to the header as specified in the event instructions. This is an example of how important it is to read the instructions carefully. I would recommend you to read through the instructions one more time before submitting your entry, as you might miss things like this.
  • The FilePath parameter is omitted on Out-File. This works fine since the parameter is positional. However, I prefer to use full parameter names when sharing scripts or even one-liners with others.
  • The instructions required a one-liner. Many people takes this literally, and place everything on one line. That is very bad for readability. This submission leverages the pipeline symbol, the comma and the back tick to continue on the next line. This is fully counted as a one-liner. However, the semi-colon as some people used does not qualify for a one-liner. This is simply a statement separator, and will break the pipeline.

The second entry I have decided to comment on is from Advanced 3:

This entry does produce a nice looking HTML-report with the required data. However, there are some bad practices I would like to highlight as learning points:

  • A ping function is created. This is not required, as PowerShell has a Test-Connection cmdlet giving the same functionality.
  • The naming of the function is not very descriptive for the end user sitting at the helpdesk.
  • The HTML code is created in a here-string rather than leveraging PowerShells ConvertTo-Html cmdlet. This makes it harder than necessary.
  • Aliases is used. This is ok when working interactively when you want to type fast, but not in a script or function you will share with others (think readability).
  • Write-Host is used (dont kill puppies), use Write-Verbose to output additional information. Alternatively, output an object even if the computer could not be contacted. You could add a “Connectivity” property to inform the user whether the computer was reachable or not, and add this to the report.

There have been many great suggestions in this event. Keep up the good work, and good luck with event 4 – “An Auditing Adventure”.

Update 2013-05-21: The good thing about the Scripting Games is that everyone learns something, including the judges. I havent been using here-strings for creating HTML, but as Rob Campbell (@mjolinor) stated on Twitter: “Here strings are an AWESOME tool for creating HTML or XML documents. ” -Jeffrey Snover. (link). Of course, this implies that you know HTML. On the topic of HTML, I would also like to recommend Don Jones` free ebook “Creating HTML Reports in PowerShell“. Available with the book is also a PowerShell module for working with HTML. In addition, there is also a very good session recording from the 2013 PowerShell Summit by Jeffrey Hicks called “Creating HTML Reports With style“.

2013 Scripting Games – Learning points from Event 1

The 2013 Scripting Games started April 25th, and event 1 is now open for voting. As I am participating as a judge this year, I will pick out two entries from each event and provide some learning points to highlight both good and bad practices.

The first entry I have decided to comment on is from Beginner 1: An Archival Atrocity.

Learning Points

  • Add comment based help. This makes it more easy for others to leverage the script, you also get the benefit of using Get-Help on your function or script.
  • The instructions did not require any output, consider using Write-Verbose instead of Write-Output. This makes it up to the user leveraging the script to decide if any output is wanted, by editing the $VerbosePreference automatic variable.
  • Avoid using aliases in scripts (Echo and Mkdir in this case), although it is great for interactive use when you want to type quickly.
  • When sharing a script, I also prefer to use full parameter names. For example Get-ChildItem -Path $RootPath instead of Get-ChildItem $RootPath.

The second entry is from Advanced 1: An Archival Atrocity.

Learning Points

  • The use of a function makes this tool easier to reuse without the need to call a script each time.
  • The use of an advanced function makes it work more like an actual cmdlet, since you can do more advanced things such as marking a parameter as mandatory and validating the arguments. For more information, see Get-Help about_Functions_Advanced.
  • This is also a good example on leveraging comment based help. All parameters is properly described, and a few examples is provided. Often the first thing people look at before reading the actual help is the examples, so it is important to provide at least a couple of them.
  • The use of parameter validation is excellent, as this simplifies the function and is leveraging functionality PowerShell is providing “for free”.
  • Default values is configured for the LogPath and Period parameters. This means that these parameter values will be used if the user using the function does not specify these parameters. It is also easy to change the values if needed, which was a requirement for this task.

There have been many great submissions for the first event. Keep up the good work, and good luck with event 2 which starts May 2.

2012 Scripting Games

The Microsoft Scripting Guys is hosting the 2012 Scripting Games April 2 – April 13 2012. The Scripting Games started out several years ago as a scripting competition based on VBScript. After the introduction of Windows PowerShell the Scripting Games did both a VBScript and a PowerShell track for a few years, until last year when VBScript was phased out in advantage of Windows PowerShell.

We can see the same thing happening in terms of automation capabilities in both Microsoft and non-Microsoft products. When we also look at the massive PowerShell capabilities coming in Windows 8 and Windows Server 8, we can see that PowerShell has turned into an essential skill for IT Professionals.

The Scripting Games is an excellent opportunity to get started with the scripting capabilities in Windows PowerShell. If you are new to PowerShell, the Beginner track is the recommended track for your first year participating in the Scripting Games. For more experienced scripters there is an Advanced track with more challenging tasks. Note that using features in the current beta of Windows PowerShell 3.0 is allowed in the Scripting Games submissions.

For those who want an introduction to PowerShell before the Scripting Games begin, Scripting Guy Ed Wilson will host a 5-series Live Meeting called “Windows PowerShell for the Busy Admin” beginning March 12, 2012.

Like last year, I will participate in the Scripting Games as a judge, which will be great fun! For those interested in learning PowerShell I highly recommend to take the time to participate in the Scripting Games, as it is a great learning experience. If your on Twitter, remember to use the 2012 Scripting Games Twitter tag #2012SG.

Good luck to all participants!


2012 Scripting Games Resources

2012 Windows PowerShell Scripting Games: All Links on One Page

2012 Scripting Games: Frequently Asked Questions

2012 Scripting Games Judging Criteria Revealed

Announcing the PowerShell Judges for the 2012 Scripting Games

TechNet Radio podcast: Announcing the 2012 Scripting Games

PowerScripting Podcast: Episode 177 – Scripting Guy Ed Wilson on the 2012 PowerShell Scripting Games

Official Scripting Guys Forum

The Scripting Guys on Facebook

The Scripting Guys on Twitter