Best Practices for PowerShell Scripting


Microsoft has released a number of recommendations for scripting in PowerShell - some of which we agree with, others we don't. For example, one good idea is to give your variables meaningful names, not just $x and $y. Some suggestions are middle-of-the-road such as suggesting that variable names use C# casing guidelines, which means a variable name would be $LogFile instead of $logfile. Whatever. The next section includes our list if best practices for PowerShell scripting:

Best Practices for Variables

  1. Give variables easy-to-read, memorable, meaningful names such as $service or $logfile. Capitalize the names however you like.

  2. To help prevent errors and make scripts more predictable and easier to debug, give variables a specific type on first use:

     [string]$var = "Hello" 

    Unlike VBScript's Option Explicit statement, PowerShell will not force you to do this, so you'll have to police yourself.

Best Practices for Scripts

  1. Give your scripts useful names. For example, a script named QueryOldUsersFromAD.ps1 is a lot more obvious than a script named GetUsers.ps1.

  2. Microsoft offers advice regarding script naming. They suggest that you name scripts using the same verb-noun format as PowerShell's cmdlets, which makes your scripts visually indistinguishable from cmdlets. For example, instead of naming a script CreateUsers.ps1, you would name it Create-User.ps1.

Singular, Not Plural

Note that PowerShell's cmdlets tend to use the singular version of nouns such as "User" rather than "Users", even if the script or cmdlet actually affects multiple objects.

We have a mixed opinion on this practice. While scripts certainly can stand in for cmdlets, they are not cmdlets. So, we will leave this practice to your personal preference: However, we will add that if you give scripts cmdlet-style, verb-noun names, make sure those scripts behave as cmdlets. This means, when appropriate, they should accept objects from the pipeline, emit objects to the pipeline, support the ubiquitous parameters supported by most cmdlets, and so forth. Otherwise, stick with useful, but not necessarily cmdlet-style, names for your scripts.

Best Practice for Parameters

  1. If your scripts or functions use input parameters, use a Param block to detail and document those. Your parameters should implement mandatory parameter checking. This means any mandatory parameters that are not provided will throw an error, and any optional parameters will have a default value:

     Function MyFunction ($required= $(paramMissing=$true), $opt = 100) {   If ($local:paramMissing) {     Throw "Required parameter 'required' is missing"   } } 

Best Practices for Aliases

This is a tough point to discuss. In some PowerShell documentation and documents, Microsoft suggests never using aliases inside a script. That's well and good, since aliases can make a script harder to read. Also, if you use an alias you've defined instead of a built-in one, then the alias might not work on every machine where the script will run. However, some aliases such as Foreach don't even seem like aliases; they seem prefer language elements. However, Foreach is actually an alias to the ForEach-Object cmdlet. .So, the question becomes, are you not supposed to use it? Therefore, the following is our recommendation when working with aliases.

  1. Use only built-in aliases, not custom aliases, in scripts.

  2. Stick with the aliases that have a meaningful name such as Foreach, but not %.

Using these two recommendation means your scripts will still be relatively easy to read and maintain. Of course, if you use PrimalScript, you can always write scripts using whatever aliases you like, and then expand all the aliases into their actual cmdlet names before you save the script and share it with others.

Best Practices for Loops and Constructs

Because all PowerShell loops and constructs end with the } character, it can be tough to tell when you've properly closed a loop. Indenting can help:

 Function MyFunction {   If ($i -gt 5) {     #code   } else {     #code   }   Function OtherFunction {     If ($i -gt 5) {       #code     } else {       #code     }   } } 

However, our best practice suggestion is that commenting the closing character helps even more:

 Function MyFunction {   If ($i -gt 5) {     #code   } else {     #code   } #end if   Function OtherFunction {     If ($i -gt 5) {       #code     } else {       #code     } #end if   } #otherfunction } #myfunction 

The ending comments help make it clearer, especially with multiple nested elements.

Best Practices for Switches

You can have your scripts support the -Debug, -Verbose, -Whatif, and, -Confirm parameters so your script can produce additional debug output, more verbose progress output, "what if" output, and so forth. For example:

 function MyFunction (   [switch]$Debug = $False,   [switch]$Verbose = $False,   [switch]$Whatif = $False,   [switch]$Confirm = $False ) {   if ($Debug) {     #provide detailed debug output   }   if ($Verbose) {     #provide verbose output   }   if ($Whatif) {     #rather than making changes,     #just display what change     #would have been made   }   if ($Confirm) {     #ask before making each change   } } 

This technique allows the script to run normally by default, since all switches are set to $False. However, if any of the switches are specified, the script's behavior is changed accordingly.

Best Practices for Comments

  1. Comment all of your scripts.

  2. Be sure to include a comment header that details what the script is intended to do and who can be contacted for support.

  3. List any prerequisites or dependencies the script may have. For example:

     # Stop-RunawayProcess.ps1 # By Don Jones - don@scriptinganswers.com # Version: 1.01 # Modified: June 11th, 2006 # Kills any process that has 99% or more CPU utilization over a # 3-minute period - use with caution! # Requires no input parameters # Has no dependencies 

  4. Include comments throughout your script that describe what's going on. For example, some comments such as the following are quite general:

     If ($i -gt $g) {   Gwmi win32_service } else {   Gwmi win32_logicaldisk } 

    Instead, use comments that more clearly explain what's going on:

     # check to see if input is > threshold If ($i -gt $g) {   # input was greater, query service   Gwmi win32_service } else {   # input not greater, query disk   Gwmi win32_logicaldisk } 



Windows PowerShell. TFM
Internet Forensics
ISBN: 982131445
EAN: 2147483647
Year: 2004
Pages: 289

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net