Hey, Scripting Guy! Question

Hey Scripting Guy! I have a question today that is not about writing a script so much as it is about testing the script after it is written. I know you have written the scripts for the Windows 7 Resource Kit, the Windows Server 2008 Resource Kit, and both editions of the Windows Vista Resource Kit, so I am sure you have some really cool methods that will simplify my life. 

-- PM

Hey, Scripting Guy! AnswerHello PM,

You are right that I (Ed) have written a lot of scripts. You mention the Windows Vista Resource Kit. I was in Edinburgh, Scotland, teaching a VBScript class while I was writing the scripts for the first edition of that book. I hiked up to the Edinburgh Castle for inspiration because I want my scripts to withstand the test of time. I took the following picture during one of these hikes (Harry Potter unavailable for comment).

Image of Edinburgh Castle


During its long history, the Edinburgh Castle has been tested several times. Luckily testing scripts does not involve building siege works.  

My testing methodology is probably not going to simplify your life—not by a long stretch. In fact, it will more than likely make it more complicated than it was previously. On the other hand, maybe your life will be simpler because you can avoid many of the mistakes I made as I was learning to test my scripts. In addition, because you will have fewer unexplained errors cropping up, perhaps that aspect alone will help to ease your troubled mind.

One of the simplest ways to test a script is to run the script. Before you run the script, however, you should examine it for obvious errors and clues to its functionality. You should pay attention to each section of the script. These sections are listed here, with a note about the types of things you should examine. You should make these checks before running the script.

In the Param section, focus on these things.

·         The command-line parameters begin with the Param keyword.

·         Each command-line parameter is separated by a comma.

·         The last parameter is not followed by a comma.

·         The parentheses should open and close.

·         Make sure the Param statement is the first noncommented line in the script.

·         Look for mandatory parameters and default values of parameters


A correctly formed Param statement is seen here:

Param(
   [string]$computer=$env:computerName,
   [switch]$disk,
   [switch]$processor,
   [switch]$memory,
   [switch]$network,
   [switch]$video,
   [switch]$all
) #end param

In the Function section, there are different items you should look for:

·         The function begins by using the Function keyword followed by the name of the function.

·         The function name should follow the verb-noun pattern in the same way that Windows PowerShell cmdlets are named.

·         Input parameters to the function are placed inside parentheses.

·         Each function parameter is separated by a comma. The last parameter is not followed by a comma.

·         Each opening curly bracket must have a corresponding closing curly bracket.

·         How are the functions called from within the script? If a function is not used in the script, it should not be stored in the script.

·         Pay particular attention to the function parameters. Which types of parameters do they require?


A correctly formed Function is seen here:

Function Get-Disk($computer)
{
 Get-WmiObject -class Win32_LogicalDisk -computername $computer
} #end Get-Disk

Now you get to the entry point of the script, which is the first code that is executed when the script runs (following the Param statement). This code is extremely important because it governs what the script will actually do.

·         What does the entry point code actually do?

·         Which variables are initialized? Are the variables released at the end of the script?

·         Which constants are declared? In what scope are the constants created?

·         Which objects are created? Which methods and properties are exposed by the new objects?

·         What are the default actions? What happens when the script is run without using any command-line parameters?

·         Does the script expose any Help?

·         Does the Help provide any examples of using the script?

·         What kind of output does the script produce? Does it output to the screen, to a text file, a database, e-mail, or some other location?

·         Is the output location from the script accessible to the workstation that runs the script?


After you have examined the script in sufficient detail, it is time to run the script. Before running the script for the first time, consider the possible impact of the script if it were to blue-screen your computer (the best place to test new scripts is in a virtual machine that has undo disks enabled):

·         Do you have any unsaved work?

·         Have you closed all unnecessary programs.

·         Have you saved the script you are working on?

·         Is the script you are working on backed up to an external drive? (This is in case the script completely wipes out your computer. If that happens, you will have a record of what the script actually did to your computer.)

·         Do you have a previously working version of the script (in case the changes to the script were radical and you might have trouble undoing them in case of disaster)?

·         Do you have a recent backup of your workstation?

 

When you run the Get-ComputerWmiInformation.ps1 script, you will see there is neither output nor feedback from the script. No errors, no output, no feedback, no help. You will need to determine how the script runs by examining the command-line parameters and the entry point to the script. Nearly all of the command-line parameters are switched parameters. The parameters have names such as $disk, $processor, $memory,  and one named $all. From this bit of information you might surmise the script retrieves information about computer hardware. From the name of the script, "Get-ComputerWmiInformation.ps1," you might determine the script uses WMI to obtain the information.

The entry point to the script calls the Get-CommandLineOptions function. An examination of the Get-CommandLineOptions function reveals that it tests for each of the command-line parameters and calls the appropriate function. Because there is no default behavior, the script ends without notice when it is run without any command-line parameters. The Get-CommandLineOptions function is seen here:

Function Get-CommandLineOptions
{
 
if($all)
  {
    Get-Disk($computer)
    Get-Processor($computer)
    Get-Memory($computer)
    Get-Network($computer)
    Get-Video($computer)
     exit
  } #end all

if($disk)
  {
    Get-Disk($computer)
  } #end disk

if($processor)
  {
    Get-Processor($computer)
  } #end processor

if($memory)
  {
    Get-Memory($computer)
  } #end memory

if($network)
  {
    Get-Network($computer)
  } #end network

if($video)
  {
    Get-Video($computer)
  } #end video
} #end function Get-CommandLineOptions

To properly test the Get-ComputerWmiInformation.ps1 script, each of the command-line parameters should be tested individually and together. In addition the script should be run remotely and locally against a variety of operating systems. You might also consider testing it on both Windows PowerShell 2.0 and Windows PowerShell 1.0. If you find that a script only runs on Windows PowerShell 2.0, it is a best practice to include the #requires –version 2.0 tag in your script. This is the only command that is permitted to go above the Param statement. However, because it begins with the pound sign, it conforms to the "first noncommented line" rule that was stated earlier.

Make sure you document how the script was tested. The version of the operating system, service pack level, and installed hotfixes all impact the way a script will run. Document all software that is installed on the computer, including management clients (such as MOM packs). If you run the script from within a script editor or directly from the command line of the Windows PowerShell console, it should be noted. If you are running on a 64-bit version of the operating system, you should test the script in both 32-bit and 64-bit Windows PowerShell. The script should be run elevated with administrator rights and with normal user rights.

The Get-ComputerWmiInformation.ps1 script is seen here.

Get-ComputerWmiInformation.ps1

Param(
   [string]$computer=$env:computerName,
   [switch]$disk,
   [switch]$processor,
   [switch]$memory,
   [switch]$network,
   [switch]$video,
   [switch]$all
) #end param

Function Get-Disk($computer)
{
 Get-WmiObject -class Win32_LogicalDisk -computername $computer
} #end Get-Disk

Function Get-Processor($computer)
{
 Get-WmiObject -class Win32_Processor -computername $computer
} #end Get-Processor

Function Get-Memory($computer)
{
 Get-WmiObject -class Win32_PhysicalMemory -computername $computer
} #end Get-Processor

Function Get-Network($computer)
{
 Get-WmiObject -class Win32_NetworkAdapter -computername $computer
} #end Get-Processor

Function Get-Video($computer)
{
 Get-WmiObject -class Win32_VideoController -computername $computer
} #end Get-Processor

Function Get-CommandLineOptions
{
 
if($all)
  {
    Get-Disk($computer)
    Get-Processor($computer)
    Get-Memory($computer)
    Get-Network($computer)
    Get-Video($computer)
     exit
  } #end all

if($disk)
  {
    Get-Disk($computer)
  } #end disk

if($processor)
  {
    Get-Processor($computer)
  } #end processor

if($memory)
  {
    Get-Memory($computer)
  } #end memory

if($network)
  {
    Get-Network($computer)
  } #end network

if($video)
  {
    Get-Video($computer)
  } #end video
} #end function Get-CommandLineOptions

# *** Entry Point to Script ***

Get-CommandLineOptions

Well, PM, that was an introduction to my script testing methodology. Join us tomorrow as we will continue to talk about testing scripts. If you want to know what we are writing and what we will be talking about in advance, follow us on Twitter. We also have a group on Facebook where we post status updates as well. We encourage you to participate in the Official Scripting Guys Forum because it is a great place to learn scripting. Until tomorrow, keep on scripting.

Ed Wilson and Craig Liebendorfer, Scripting Guys