PowerShell Summit 2014: Reviewing the Iron Scripter

I’ve been pretty busy, lately. It’s taken a while for me to finally get around to looking at the Iron Scripter challenge, alongside the winning code, that went on at the PowerShell Summit this past April. How did the challenge work?

Participants were awarded 1-5 points in each of the following categories:

  • Presentation (formatting)
  • Creativity
  • Use of the Theme Ingredient (being CIM)
  • Taste (functionality)

The challenge was made up of three courses:

  • Appetizer Course
  • Dessert Course
  • Main Course

You can find the actual questions nicely detailed at Francois-Xavier Cat’s blog. There you can also see the amazing award trophy, grenade included, which was won by Kendall Maddox. The winning code is actually available in the scripts/slides download on PowerShell.Org’s resource page for the summit. So let’s breakdown the winning code:

Appetizer

From Francois-Xavier Cat’s blog link above, here was the wanted output:

Appetizer

Winning code:

"localhost" |
  gcim win32_operatingsystem |
  select PSComputerName,Version,BuildNumber,
    @{n="BIOSSerial";e={(gcim win32_bios).SerialNumber}}

This was a timed event, so we were being graded on closest solution/best formatting/etc. Here is a slightly modified version of the code that pushes the output to appear to the letter:

@("client","localhost") |
  gcim win32_operatingsystem |
  ft PSComputerName,Version,BuildNumber,
    @{n="SP";e={(gcim win32_operatingsystem).servicepackmajorversion}},
    @{n="BIOSSerial";e={(gcim win32_bios).SerialNumber}} -a

Note: Using Format-Table (“ft” alias above) prevents the object output from properly entering the pipeline. This is only to match the image output exactly, otherwise we would stick with using Select-Object (“select” alias above) if you were piping this output into another function/cmdlet.

Dessert

From Francois-Xavier Cat’s blog link above, here was the broken and badly formatted function that needed attention:

Dessert

Winning code:

function Get-Sysinfo{
  [cmdletBinding()]
  Param(
    [Parameter(Mandatory=$true,
      ValueFromPipeLine=$True)]
    [string[]]$ComputerName
  )
  Process{
    foreach($computer in $computerName){
      Try{
        Write-Output "Trying $computer"
        $bios = Get-CimInstance Win32_Bios -ComputerName $computer -ea stop
        $os = Get-CimInstance Win32_OperatingSystem -ComputerName $computer
        $props = @{'ComputerName'=$computer;
                   'BIOSSerial'=$bios.SerialNumber;
                   'OSVersion'=$os.Version
        }
        $obj = New-Object -TypeName PSObject -Property $props
        write-output $obj
      }
      Catch{
        Write-Warning "uh, oh $($computer)"
      }
    }
  }
}

Main Course

The Main Course is listed last, because finding the solutions to the Appetizer and Dessert challenges practically set you up for success. The output shown for this portion (as scanned/copied at Francois-Xavier Cat’s blog — did I mention his blog yet?) was asking for the Dessert Get-Sysinfo function to provide the following — each bullet-point represents each example run of the command in Main Course hand-out:

  • Get-Sysinfo must provide custom Verbose output when using the -Verbose common parameter
  • Get-Sysinfo should only output objects to the pipeline when not using the -Verbose common parameter
  • Get-Sysinfo must be able to take an array of strings for the -ComputerName parameter, and must also be enabled for taking ValueFromPipeline
  • Get-Sysinfo must be using -ComputerName as a Mandatory parameter, and it should be providing ComputerName, BIOSSerial, and OSVersion — each as a returned NoteProperty

The winning code:

function Get-Sysinfo{
  [cmdletBinding()]
  Param(
    [Parameter(Mandatory=$true,
      ValueFromPipeLine=$True)]
    [string[]]$ComputerName
  )
  Process{
    foreach($computer in $computerName){
      Try{
        Write-verbose "Trying $computer"
        $bios = Get-CimInstance Win32_Bios -ComputerName $computer -ea stop
        $os = Get-CimInstance Win32_OperatingSystem -ComputerName $computer
        $props = @{'ComputerName'=$computer;
                   'BIOSSerial'=$bios.SerialNumber;
                   'OSVersion'=$os.Version
        }
        $obj = New-Object -TypeName PSObject -Property $props
        write-output $obj
      }
      Catch{
        Write-Warning "uh, oh $($computer)"
      }
    }
  }
}

A breakdown of how this fulfilled the requirements:

  • The [CmdletBinding()] on line 2 provides Common Parameters, such as -Verbose, to be available for the function. When using the parameter, anything marked as Write-Verbose will now appear as output when running, and any other functions/cmdlets within will run with a -Verbose parameter if it is available for use (which Get-CimInstance is able to provide).
  • Since there are no other lines within the script for Write-Host (Jeffrey Snover’s friendly message: Please don’t use Write-Host), or Write-Output (other than for outputting the objects themselves), only the objects are returned from the function when not using common parameters like -Verbose.
  • When declaring [Parameter(Mandatory=$True,ValueFromPipeLine=$True)][String[]]$ComputerName, this fulfilled the following challenge requests: -ComputerName is a mandatory parameter (Mandatory=$True) that can accept multiple strings ([String[]] as opposed to [String]), even from the pipeline (ValueFromPipeline=$True).
  • The $props hash table fulfilled the requested output NoteProperty names and values that the resulting PSObjects contain.

And that is how the Iron Scripter challenge is full of “You might not know this about PowerShell Scripting” knowledge-nuggets.

Side Note: Originally, the challenge noted that you cannot use semicolons in your code. Though, they corrected this statement as they were originally meaning that you cannot not use semicolons to run multiple lines of code as one line of code (specifically in regards to the Appetizer challenge). This threw some people off, but once the thumbs up was given, hash tables and substitution were fair game!

Miscellaneous Links

[Twitter] Rob Campbell: Trophy Builder Extraordinaire and PowerShell Evangelist 
[Twitter] Kendall Maddox: Iron Scripter Champion

3 thoughts on “PowerShell Summit 2014: Reviewing the Iron Scripter

  1. Great post man! I read the link to the ‘Why not to use Write-Host’ like you mentioned yesterday and now I can see why.

    Eric

Leave a comment