Mr Andersson

PowerShell Scripting Guidelines

leave a comment »

Lately I have been doing some work related to how we automate the process of how we install, configure and deploy our product into a server environment. Since our pre-requisites are Windows Server 2008 and Windows 7, we can totally go crazy with PowerShell scripts. Next thing to sort out after upgrading to Windows Server 2008 R2 is of course PowerShell Remoting.. :)

However, using quite an amount of PowerShell scripts, we need some guidelines to structure them. This to complement our guidelines covering OO design and C# code style.

So I have started out with the following draft and I’m looking for some tips and comments about this and what you (yes, you!) believe is a good rule of thumb to use when developing and maintaining a bunch of PowerShell scripts.

(Sorry for the ugly formatting. Code was pasted from PowerGUI to a word doc and then to blogger :) )

1 Scripting Guidelines

When there is a need of a script, use your mighty PowerShell skills!
Here is a couple of guidelines which should be followed to speed up development, maintenance and usage of PowerShell scripts.

Apply the above mentioned principles when applicable.

1.1 Function files

Package common functions into function files and dot-source them in the script which needs them.
Example:
. ..\DB\Common.ps1

1.2 File names

Name PS1 files using standard verbs like get, set, remove, new etc., or a verb that fits the purpose or the script. Do not use verbs in file names for files that have generic purpose, like a function library file. Also consider using PowerShell v2 modules when applicable.

Scripts that are to be called from the prompt are easier to understand if they are named in such way that no “usage” or get-help is needed when invoking the script. Like add-user.ps1, remove-database.ps1 and so on.

Avoid complex scripts with multiple purposes which becomes complex with parameter sets (get-help about_functions_advanced_parameters)

1.3 Script and function parameters

Use built-in support to handle function and script parameters. Avoid index-based unnamed parameters using $args.

Reference: get-help about_arguments; get-help about_functions; get-help about_functions_advanced_parameters
MSDN:
http://msdn.microsoft.com/en-us/library/ms714433(VS.85).aspx

Example, testme.ps1:

param(

[Switch] $ver = [Switch]::Present

)

Write-Host $args

Write-Host “Testing!”

if( $ver )

{

Write-Host “Testing even more!”

}

Output:

PS > .\testme.ps1 –ver
PS > .\testme.ps1 -ver:$false

1.4 Decorate function parameters appropriately using validation rules

Decorate your parameters with validation rules and help messages to avoid tedious work on custom “script usage” functions. Your script users will be able to use “get-help yourscript.ps1”, or the equivalent “yourscript.ps1 -?” to get script usage information. Users will also be prompted if mandatory parameters are left out blank.

Get-help will also print out common parameters (get-help about_commonparameters).

Example:

param(

[Switch] $ver = [Switch]::Present,

[Parameter(mandatory=$true, helpmessage="Your name")]

[ValidateNotNullOrEmpty()]

[string] $name = “John Doe”

)

Write-Host $args

Write-Host “Hello $name!”

if( $ver )

{

Write-Host “Your name is $($name.Length) characters long”

}

Output:

PS > get-help .\testme.ps1

testme.ps1 [-name] [-ver] [-Verbose] [-Debug] [-ErrorAction ] [-WarningAction ] [-ErrorVariable ] [-WarningVariable ] [-OutVariable ] [-OutBuffer ]

1.5 Document script usage using PowerShell comment based help

When it is necessary to document how a script can be used, or when you want to provide more information about your script’s parameters than just the name, document it using the PowerShell help syntax. This can be compared to using XML comments in languages such as C#/VB or javadoc tags in Java.

See “get-help about_comment_based_help” for more information.

Example:

<#

.Synopsis

Synopsis text here

.Description

Usage description here

.Parameter ver

Enabling this switch prints out the length of the given name

.Parameter name

The name to say hello to

#>

param(

[Switch] $ver = [Switch]::Present,

[Parameter(mandatory=$true, helpmessage="Your name")]

[ValidateNotNullOrEmpty()]

[string] $name = “John Doe”

)

Write-Host $args

Write-Host “Hello $name!”

if( $ver )

{

Write-Host “Your name is $($name.Length) characters long”

}

Output:
PS> get-help -full .\testme.ps1

NAME
C:\temp\testme.ps1

SYNOPSIS
Synopsis text here

SYNTAX
C:\temp\testme.ps1 [-ver] [-name] []

DESCRIPTION
Usage description here

PARAMETERS
-ver []
Enabling this switch prints out the length of the given name

Required? False
Position? Named
Default value
Accept pipeline input? False
Accept wildcard characters?

-name
The name to say hello to

Required? True
Position? 1
Default value
Accept pipeline input? False
Accept wildcard characters?


This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
“get-help about_commonparameters”.

INPUTS

OUTPUTS

RELATED LINKS

1.6 Use validation rules to perform parameter input validation

PowerShell has several built-in validation rules for input validation. Use them as long as they add more value than doing custom validation using if-statements.

The built-in validation rules are: AllowNull, AllowEmptyString, AllowEmptyCollection, ValidateCount, ValidateLength, ValidatePattern, ValidateRange, ValidateScript, ValidateSet, ValidateNotNull, ValidateNotNullOrEmpty
See “
get-help about_functions_advanced_parameters” for further reference.

1.7 Putting the right stuff on the pipeline

· Use write-host for console information with fancy colors

· Use write-output to be able to pipe your script/function to another script/function.
Example pipeline scenario, sending a user from add-user to new-guestbookentry:
. .\guestbooks-functions.ps1;
add-user “foo” “password” | new-guestbookentry “Welcome to our guestbooks.com!”

· Avoid unwanted objects on the pipeline using termination with $null assignments or piping the output to NULL, example:
add-user “foo” “password” # put the added user on the pipeline
$null = add-user “foo” “password” # added user object “terminated”
add-user “foo” “password” | out-null # added user object piped to NULL instead of the output

Advertisement

Written by anderssonjohan

October 21, 2009 at 12:57

Posted in scripting

Tagged with

Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

Please log in to WordPress.com to post a comment to your blog.

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.