Designing Help Documentation for Windows PowerShell Scripts

  • 12/16/2009
In this chapter from Windows PowerShell 2.0 Best Practices, you will look at proven methods for providing custom help in Windows PowerShell scripts.
  • Adding Help Documentation to a Script with Single-Line Comments 331

  • Using the Here-String for Multiple-Line Comments 335

  • Using Multiple-Line Comment Tags in Windows PowerShell 2.0 355

  • The 13 Rules for Writing Effective Comments 357

  • Additional Resources 372

Although well-written code is easy to understand, easy to maintain, and easy to troubleshoot, it can still benefit from well-written help documentation. Well-written help documentation can list assumptions that were made when the script was written, such as the existence of a particular folder or the need to run as an administrator. It also documents dependencies, such as relying on a particular version of the Microsoft .NET Framework. Good documentation is a sign of a professional at work because it not only informs the user how to get the most from your script, but it also explains how users can modify your script or even use your functions in other scripts.

All production scripts should provide some form of help. But what is the best way to provide that help? In this chapter, you will look at proven methods for providing custom help in Windows PowerShell scripts.

When writing help documentation for a script, three tools are available to you. The first tool is the traditional comment that is placed within the script—the single-line comment that is available in Windows PowerShell 1.0. The second tool is the here-string. The third tool is the multiple-line comment that is introduced in Windows PowerShell 2.0. Once you understand how to use these tools, we will focus on the 13 rules for writing effective comments.

Adding Help Documentation to a Script with Single-Line Comments

Single-line comments are a great way to quickly add documentation to a script. They have the advantage of being simple to use and easy to understand. It is a best practice to provide illuminating information about confusing constructions or to add notes for future work items in the script, and they can be used exclusively within your scripting environment. In this section, we will look at using single-line comments to add help documentation to a script.

In the CreateFileNameFromDate.ps1 script, the header section of the script uses the comments section to explain how the script works, what it does, and the limitations of the approach. The CreateFileNameFromDate.ps1 script is shown here.

Example 10-1. CreateFileNameFromDate.ps1

# ------------------------------------------------------------------------
# NAME: CreateFileNameFromDate.ps1
# AUTHOR: ed wilson, Microsoft
# DATE:12/15/2008
#
# KEYWORDS: .NET framework, io.path, get-date
# file, new-item, Standard Date and Time Format Strings
# regular expression, ref, pass by reference
#
# COMMENTS: This script creates an empty text file
# based upon the date-time stamp. Uses format string
# to specify a sortable date. Uses getInvalidFileNameChars
# method to get all the invalid characters that are not allowed
# in a file name. It assumes there is a folder named fso off the
# c:\ drive. If the folder does not exist, the script will fail.
#
# ------------------------------------------------------------------------
Function GetFileName([ref]$fileName)
{
 $invalidChars = [io.path]::GetInvalidFileNamechars()
 $date = Get-Date -format s
 $fileName.value = ($date.ToString() -replace "[$invalidChars]","-") + ".txt"
}

$fileName = $null
GetFileName([ref]$fileName)
new-item -path c:\fso -name $filename -itemtype file

In general, you should always provide information on how to use your functions. Each parameter, as well as underlying dependencies, must be explained. In addition to documenting the operation and dependencies of the functions, you should also include information that will be beneficial to those who must maintain the code. You should always assume that the person who maintains your code does not understand what the code actually does, therefore ensuring that the documentation explains everything. In the BackUpFiles.ps1 script, comments are added to both the header and to each function that explain the logic and limitations of the functions as shown here.

Example 10-2. BackUpFiles.ps1

# ------------------------------------------------------------------------
# NAME: BackUpFiles.ps1
# AUTHOR: ed wilson, Microsoft
# DATE: 12/12/2008
#
# KEYWORDS: Filesystem, get-childitem, where-object
# date manipulation, regular expressions
#
# COMMENTS: This script backs up a folder. It will
# back up files that have been modified within the past
# 24 hours. You can change the interval, the destination,
# and the source. It creates a backup folder that is named based upon
# the time the script runs. If the destination folder does not exist, it
# will be created. The destination folder is based upon the time the
# script is run and will look like this: C:\bu\12.12.2008.1.22.51.PM.
# The interval is the age in days of the files to be copied.
#
# ---------------------------------------------------------------------
Function New-BackUpFolder($destinationFolder)
{
 #Receives the path to the destination folder and creates the path to
 #a child folder based upon the date / time. It then calls the New-Backup
 #function while passing the source path, destination path, and interval
 #in days.
 $dte = get-date
 #The following regular expression pattern removes white space, colon,
 #and forward slash from the date and replaces with a period to create the
 #backup folder name.
 $dte = $dte.tostring() -replace "[:\s/]", "."
 $backUpPath = "$destinationFolder" + $dte
 $null = New-Item -path $backUpPath -itemType directory
 New-Backup $dataFolder $backUpPath $backUpInterval
} #end New-BackUpFolder

Function New-Backup($dataFolder,$backUpPath,$backUpInterval)
{
 #Does a recursive copy of all files in the data folder and filters out
 #all files that have been written to within the number of days specified
 #by the interval. Writes copied files to the destination and will create
 #if the destination (including parent path) does not exist. Will overwrite
 #if destination already exists. This is unlikely, however, unless the
 #script is run twice during the same minute.
 "backing up $dataFolder... check $backUppath for your files"
 Get-Childitem -path $dataFolder -recurse |
 Where-Object { $_.LastWriteTime -ge (get-date).addDays(-$backUpInterval) } |
 Foreach-Object { copy-item -path $_.FullName -destination $backUpPath -force }
} #end New-BackUp

# *** entry point to script ***

$backUpInterval = 1
$dataFolder = "C:\fso"
$destinationFolder = "C:\BU\"
New-BackupFolder $destinationFolder