Home Scripting Games Scripting Games Task #2 Commentary

Scripting Games Task #2 Commentary

Scripting Games event #2 has closed, and again I take the chance to comment some of the techniques used.

You all did a great job! Many of you used very creative solutions, and sometimes you made your life harder than it needs to be. So let’s take a look at some PowerShell techniques I’d recommend.

Make Functions First-Class-Citizen: Return Objects!

To make your PowerShell functions versatile and compatible to other cmdlets, always return information as an object. This ensures that the results provided by your function can be piped to whatever else cmdlet you might want to use to filter and/or output the information. Only then is your function a full first class citizen and versatile enough to be combined with other cmdlets.

Some of you created a new object and added NoteProperties to it using Add-Member which is perfectly good to do. If all you need are note properties, an easier way is to use Select-Object. Select-Object can select existing properties, but it can also add new ones.

Just compare these two pieces of code:

$CurrentObject = New-Object System.Object
$CurrentObject | Add-Member -MemberType NoteProperty -Name Computername -Value $Computer
$CurrentObject | Add-Member -MemberType NoteProperty -Name OSCaption -Value $null
$CurrentObject | Add-Member -MemberType NoteProperty -Name OSServicePack -Value $null
$CurrentObject | Add-Member -MemberType NoteProperty -Name OSVersion -Value $null
$CurrentObject | Add-Member -MemberType NoteProperty -Name RAMCapacity -Value $null
$CurrentObject | Add-Member -MemberType NoteProperty -Name CPUPhysical -Value $null
$CurrentObject | Add-Member -MemberType NoteProperty -Name CPUCores -Value $null
$CurrentObject | Add-Member -MemberType NoteProperty -Name CPULogical -Value $null
$CurrentObject | Add-Member -MemberType NoteProperty -Name Status -Value $null

Versus this one:

$CurrentObject = 'dummy' | Select-Object -Property ComputerName, OSCaption, OSServicePack, OSVersion, RAMCapacity, CPUPhysical, CPUCores, CPULogical, Status

The result is the same.

Others used this approach:

$Data = [Ordered]@{
                    'OSName' = $OperatingSystem.Caption;
                    'OSBuild' = $OperatingSystem.BuildNumber;
New-Object -TypeName PSObject -Property $Data

Congratulations! This is the most efficient approach. The hash table holds properties and values, and New-Object turns this into an object.

Note however that [Ordered] is new in PowerShell 3.0 and won’t work in PowerShell 2.0. If you omit it, the resulting object will still work fine, but the properties may appear in random order.

Avoid Strict Mode

Some of you used Set-StrictMode in your scripts. That’s not a good idea.

While enabling strict mode can help you write better scripts by forcing you to declare variables and stick to a number of other rules, enabling strict mode in production scripts is actually dangerous. It is just a tool for you as a script author and should only be enabled on development machines.

You simply never know the environment in which your function will run. Some scripts depend on the normal PowerShell behavior and break if strict mode is enabled. In addition, adding Set-StrictMode to your function will do no good. If your code adheres to strict mode, nothing happens. It if doesn’t, an error is raised that should have been caught during script development.

So never force other users to adhere to PowerShells strict mode by adding this statement to your production code. PowerShells default mode is not strict mode – for a reason.

Use .NET Objects and Casting

Most of you used WMI to discover the OS version which is a good idea:

$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName


To discover the major version, you can use a number of techniques including regular expressions, but in my opinion a pretty simple way is to cast the string version to a version type like this:


This way, one simple line can get you the major version number.

Use MB and GB shortcuts

Compare these two pieces of code:

$MB = 1024 * 1024

PowerShell already defines the sizes for KB, MB, GB, and PB.

Using -Credential

Most of you used Get-WMIObject to connect to servers and get the information requested. If you want to authenticate, you can use the parameter -Credential, but you cannot use this parameter with local machines. So how can you submit this parameter on a case by case basis?

Here’s how: use splatting!

if ($Credential) {
 $hash = @{'Credential'=$Credential}
} else {
  $hash = @{}

Get-WmiObject -ComputerName $Computer -Class Win32_OperatingSystem @hash

The hash table holds the parameter you want to assign plus its value. So if you leave the hash table empty, no parameter is used. If you add a key named ‘Credential’, then the credential parameter is used with the value provided in the hash table. A very elegant solution.