Scripting Games 2013: Event 3 Notes

Wow, it is hard to believe that we are now halfway through the Scripting Games! As the events have progressed, I have seen a lot of improvement with the techniques as well as seeing new techniques that continue to impress me. On the flip side, I have seen some mistakes or assumptions when coding that cause a potential 5 star script to be a 2 or 3 star script. The best part about all of this is that we are all (yes, even the judges) learning new things that can only help to improve everyone’s scripting knowledge.

With that, it is time to take a look at the things that could be improved upon or should be avoided altogether.

-Filter vs. Where-Object

This was probably the biggest issue I have seen with the submissions for Event 3. Too many submissions were taking the output of Get-WMIObject and piping the results into Where-Object to get all of the local hard drives. The sooner you get used to working with –Filter, the better off you will be working with scripts and one liners to query WMI on both local and remote systems. When you use the Filter parameter, especially on remote systems, the filtering is performed on the remote system and only the objects that you filtered for will be passed back to the local system.

Some people claim that it is an ugly approach and I disagree. If I am looking for only hard drives, which one looks worse:

Filter

drivetype=3

Where-Object

$_.drivetype –eq 3

To me, the obvious answer is using Filter and supplying the WQL statement. Sure the statements may get complicated, but so could using the Where-Object. And if you might not be sure as to what type of WQL statement to use, simply look it up. There are plenty of resources available that you can use to figure out the proper query.

I’ve also heard that performance was the reason for using Where-Object locally vs. –Filter and that it isn’t much better to consider using the –Filter parameter. Lets compare performance just to see.

Filter

(Measure-Command {
    Get-WmiObject -Class Win32_LogicalDisk -Filter 'drivetype=3'
}).TotalMilliseconds

image

 

Where-Object

(Measure-Command {
    Get-WmiObject -Class Win32_LogicalDisk | Where {
        $_.driveType -eq 3
    }
}).TotalMilliseconds

image

About a 50 millisecond difference. Pretty good difference to me. Some might disagree, but the fact is that using –Filter has better performance. So why is that the case? Let’s take a closer look at each command. If you know PowerShell, you know that Where-Object takes the input from whatever command is before it in the pipeline and starts performing a comparison against the object in the pipeline based on the data you provide.

Get-WmiObject -Class Win32_LogicalDisk | Where {
    Write-Verbose $_ -Verbose
    $_.driveType -eq 3
}
 

image

As you can see, each object is being looked at when just using Where-Object. I wonder what happens when I use the –Filter parameter…

Get-WmiObject -Class Win32_LogicalDisk -Filter 'drivetype=3' | Where {
    Write-Verbose $_ -Verbose
}

image

Instead of going through 4 items, I only see the 3 that are actual hard drives. This is the efficiency of using a parameter on ANY cmdlet vs. using Where-Object.

So bottom line: –Filter is not only a best practice for Get-WMIObject, but it is also more efficient and provides better performance.

Hard Coded Paths

Something that was driving me crazy during this event, especially on the beginner side was the use of hard coded paths to output the html file. When you use a path such as C:\smith\awesomefolder as the directory, you cannot expect it to work for me. I shouldn’t have to modify your code to make it work for me. It should work without any issues. The solution for this would be to use something like $pwd, or also in some scripts I saw (good job, by the way!), $Env:TEMP  or $Env:USERPROFILE. There are other possibilities, but the main thing is that you must make sure that it is universal to the everyone who uses it.

.Net Types

This is the PowerShell scripting games, not the .Net games. Don’t use [DateTime]::now, when there is a perfectly good cmdlet called Get-Date that will accomplish the same thing. I even saw this: [environment]::MachineName being used. Really? You can get the same thing out of $Env:Computername.

Another person took the time to create their own network checker using System.Net.NetworkInformation.Ping. The same thing can be done by using Test-Connection.

Unless there is compelling need to use this (haven’t seen it yet) to use a .Net type to accomplish your goal, stick with the cmdlets and you will be better off.

Over Commenting

This is pretty self explanatory. We don’t need a 2-3 line comment talking about how you are querying WMI on a local system and then continuing this trend for each and every line of code. Not every line of code requires a comment, let along multiple lines of commenting. Keep it simple and clean and everything will be Ok.

Some Final Points

  • Consider use of [pscustomobject] vs. Net-Object PSObject for V3 code
  • Stop using back ticks as line breaks.
  • If the event says to do a one line, then you should shoot for a one liner and avoid using semicolons because it is no longer a one liner.
  • No more concatenating (Ex: “this” + $something + “is great!”). We are not in the vbscripting games.
  • Also avoid using += to append lines to an existing variable. Use a Here-String instead.

Keep up the great submissions and I am looking forward to seeing what you do with Event 4!

This entry was posted in powershell, Scripting Games 2013 and tagged , , , . Bookmark the permalink.

4 Responses to Scripting Games 2013: Event 3 Notes

  1. Pingback: The 2013 Scripting Games, Beginner Event #3 | Mello's IT Musings

  2. cseiter says:

    I am definitely guilty of over-commenting, but there is some method to my madness. I only use the NOTES section and I try to spell out either what issues I ran in to or why I did a certain thing rather than another. If I can show my thinking, then maybe my thinking can be corrected and I can be told why it’s wrong rather than just what’s wrong.

  3. Absolutely agree about the .NET coding. If you want to write .NET than by all means crank up Visual Studio and have at it. Use of .NET classes and methods in a PowerShell script should be an exception when nothing else will do. I also use to think using .NET was ok for reasons of performance. But if your performance needs are so great, then a PowerShell script may not be the right tool of choice anyway and a compiled .NET program might be better.

  4. Pingback: Scripting Games 2013: Event 3 Notes | PowerShell.org

Leave a comment