Avoiding PowerShell Scripting Pitfalls

Avoiding PowerShell Scripting Pitfalls

  • Comments 2
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, shares an excerpt from his book, Windows PowerShell Best Practices that discusses scripting pitfalls.

Microsoft Scripting Guy, Ed Wilson, is here. Today I have an excerpt from my new book, PowerShell Best Practices, which is published by Microsoft Press. In the excerpt today, I talk about avoiding Windows PowerShell scripting pitfalls. This is something that I saw a lot when I was judging the Scripting Games entries.

Image of book

Complicated constructors

If you do not have support from cmdlets when you develop an idea for a script, this indicates that there may be a better way to do something, and it should cause you to at least consider your alternatives.

In the following script, GetRandomObject.ps1, a function named GetRandomObject is created. This function takes two input parameters—one named $in that holds an array of objects and the other named $count that controls how many items are randomly selected from the input object.

The New-Object cmdlet is used to create an instance of the System.Random Microsoft .NET Framework class. The new instance of the class is created by using the default constructor (no seed value is supplied), and it is stored in the $rnd variable.

A for . . . next loop is used to loop through the collection—once for each selection desired. The next method of the System.Random class is used to choose a random number that resides between the number 1 and the maximum number of items in the input object. The random number is used to locate an item in the array by using the index so that the selection of the item from the input object can take place. The GetRandomObject.ps1 script is shown here:

GetRandomObject.ps1

Function GetRandomObject($in,$count)
{
 $rnd = New-Object system.random
 for($i = 1 ; $i -le $count; $i ++)
 {
  $in[$rnd.Next(1,$a.length)]
 } #end for
} #end GetRandomObject

# *** entry point ***
$a = 1,2,3,4,5,6,7,8,9
$count = 3
GetRandomObject -in $a -count $count

Although there is nothing inherently wrong with the GetRandomObject.ps1 script, you can use the Get-Random cmdlet when you work with Windows PowerShell 2.0 to accomplish essentially the same objective, as shown here:

$a = 1,2,3,4,5,6,7,8,9
Get-Random -InputObject $a -Count 3

Clearly, by using the native Get-Random cmdlet, you can save yourself a great deal of time and trouble. The only reason to use the GetRandomObject.ps1 script is that it works with both Windows PowerShell 2.0 and Windows PowerShell 1.0.

One advantage of using a cmdlet is that you can trust it will be implemented correctly. At times, .NET Framework classes have rather complicated constructors that are used to govern the way the instance of a class is created. A mistake that is made when passing a value for one of these constructors does not always mean that an error is generated. It is entirely possible that the script will appear to work correctly, and therefore, it can be very difficult to see the problem.

An example of this type of error is shown in the BadGetRandomObject.ps1 script in which an integer is passed to the constructor for the System.Random .NET Framework class. The problem is that every time the script is run, the same random number is generated. Although this particular bad implementation is rather trivial, it illustrates that the potential exists for logic errors that often require detailed knowledge of the utilized .NET Framework classes to troubleshoot.

BadGetRandomObject.ps1

Function GetRandomObject($in,$count,$seed)
{
 $rnd = New-Object system.random($seed)
 for($i = 1 ; $i -le $count; $i ++)
 {
  $in[$rnd.Next(1,$a.length)]
 } #end for
} #end GetRandomObject

# *** entry point ***
$a = 1,2,3,4,5,6,7,8,9
$count = 3
GetRandomObject -in $a -count $count -seed 5

Join me tomorrow when I have a guest blog post written by Microsoft technical evangelist, Keith Mayer, about working with Windows Azure.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Good One!!! One thing to promote PowerShell $a = 1..9 :) :) :). Function GetRandomObject($in,$count) { $rnd = New-Object system.random for($i = 1 ; $i -le $count; $i ++) { $in[$rnd.Next(1,$a.length)] } #end for } #end GetRandomObject # *** entry point *** #$a = 1,2,3,4,5,6,7,8,9 $a = 1..9 $count = 3 GetRandomObject -in $a -count $count

  • The line within the FOR loop contains a typo? Wrong: $a.length Right: $in.length