Summary: Microsoft Windows PowerShell MVP, Sean Kearney, continues a series of guest blogs detailing building your own cmdlet.
Microsoft Scripting Guy, Ed Wilson, is here. Guest blogger and Windows PowerShell MVP, Sean Kearney, has written a series about building cmdlets. For more about Sean, see his previous guest blog posts.
Note This is Part 8 of a nine-part series about building your own Windows PowerShell cmdlet. Read the entire series as it unfolds.
Here’s Sean…
Having a cmdlet to help make life easier is one thing. Enabling others to easily understand how to leverage it is an especially wonderful thing. Within Windows PowerShell, you can easily produce Help for your users in the scripts by using what is referred to as comment-based Help.
The same feature carries directly into your cmdlets and works in exactly the same way. Normally within Windows PowerShell when you precede something with a pound character (#) everything after that is recognized as a comment within the script. You can leverage this within the Windows PowerShell environment to easily build-in Help for your scripts and cmdlets.
Comment-based Help is produced within an advanced function or Windows PowerShell script by leveraging comments that are defined with specific keywords, and then laying them out in specific sections at the beginning or end of a script or advanced function.
My personal preference is to place the Help near the beginning of the script block—placing the “how to use this” near the top—but that’s simply a personal preference. In actual fact, the comment-based Help can sit in multiple locations with the cmdlet or script.
You can place your Help block right after the naming of the function, at the bottom of the script, or prefacing the name.
Note If you place it before the name of the function, there can be no space separating the two.
When you write the comment-based Help, your block will begin and terminate in one of the following two fashions.
<#
.keyword
Descriptive Text
#>
Or:
# .keyword
# Descriptive Text
When I have to choose a style, my own personal preference is beginning <# and ending with #>. In that way, I look and know where the start and end of my comment-based Help is.
For comment-based Help, you have the following keywords to leverage. Each time you use a keyword, it must be preceded with a period (.).
-
.SYNOPSIS
-
.DESCRIPTION
-
.PARAMETER
-
.EXAMPLE
-
.INPUTS
-
.OUTPUTS
-
.NOTES
-
.LINK
-
.COMPONENT
-
.ROLE
-
.FUNCTIONALITY
-
.FORWARDHELPTARGETNAME
-
.REMOTEHELPRUNSPACE
-
.EXTERNALHELP
Comment-based Help keywords
Each of these keywords has their own special use and format. I’ll try to provide a very compressed version of their meaning.
SYNOPSIS
A very quick description of the cmdlet or script. Think in your head, “If I had to say what this cmdlet does in twelve words or less, what would they be?” Of course, the synopsis can be longer, but my personal feeling is, “The boss is asking you what this does, so be quick, brief, and to the point.”
DESCRIPTION
This is where you can get chatty. Get very descriptive if you like, and be liberal with words to describe what the cmdlet does and how it works. Use whatever text is most appropriate. Perhaps you want to provide a long story about the day you and the cmdlet went for supper in a quaint little diner in Albuquerque.
PARAMETER
For each parameter that your cmdlet or script is accepting, you can place a spot to describe what that parameter does, and what type of data it is expecting and wanting. You can place as many of these entries as you have parameters.
EXAMPLE
My greatest love in Windows PowerShell is when people who build cmdlets give me real world examples of how they work and how they can work. This is your time to show how your cmdlet will shine. You can provide as many examples as you want. Use an EXAMPLE keyword and descriptive lines for each example you provide.
Show people what the cmdlet does in a pipeline and what it does by itself. Give interactive examples. The more people have of examples of how your cmdlet can be used, the more likely it will be used. Unless, of course, your cmdlet is meant to write, “Hello, I am cool!” all over on the screen, infinitely, in random colors. Then there is a very good chance that it won’t get used—no matter how many examples you provide.
INPUTS and OUTPUTS
INPUTS and OUTPUTS are similar and related within the Help system. INPUTS are whatever types of objects your cmdlet can accept from the pipeline. OUTPUTS are whatever type of objects you are returning. If you’d like to describe this type of data, here is the place to put it
NOTES
Anything that isn’t covered in the previous keywords. It could be a trivial pursuit about your cmdlet if you feel so inclined, or maybe even information about how much time your cmdlet saved you at work. Write whatever you feel is relevant—even something as trivial as, “Whatever you do, don’t run this on the production Exchange Server—I wish I didn’t.”
LINK
Links to other topics about your cmdlet, maybe resources you used. It can be as simple as, “Here is the link to my website to send me money, complaints, or Jelly Babies.”
COMPONENT
“What does my script need to work? What dependencies does it need? Will it work with Novell?” These are questions you should answer for your users. For example, “My cmdlet requires the Quest ActiveRoles Server component to function.” The wording, of course, is your own, but this is your opportunity to state what prerequisites you need.
EXTERNALHELP
When you see EXTERNALHELP, it is not a phone call to your friend down the road. EXTERNALHELP is a link to a file outside of the module or cmdlet. If we want to place some sample Help in our cmdlet, the block could look like this, depending on what details you want to provide for the cmdlet.
function global:ADD-LOGFILE{
<#
.SYNOPSIS
This Cmdlet Creates a Blank Logfile
.DESCRIPTION
This Cmdlet Creates a Blank Logfile in any specified folder, assigned preface or file extension. It will default to the location C:\Logfile with an extension of .TXT
.EXAMPLE
ADD-LOGFILE
Creates a Logfile in C:\Logfile folder
.EXAMPLE
ADD-LOGFILE C:\Here
.EXAMPLE
ADD-LOGFILE -Extension .FIL
.NOTES
Creates logfiles based upon Date and Time
.LINK
#>
[CmdletBinding(
DefaultParameterSetName=”Folder”,
SupportsShouldProcess=$True,
ConfirmImpact=’High’
)]
PARAM(
[parameter(Mandatory=$True,
ValueFromPipeline=$True,
Position=0,
HelpMessage=’Folder to Store Logfiles in’)]
[STRING[]]$Folder="C:\PowerShell",
[parameter(ValueFromPipeline=$True,
Position=1,
HelpMessage=’TEXT to prepend all logfiles with’)]
[STRING[]]$Preface="Logfile",
[parameter(ValueFromPipeline=$True,
Position=1,
ValueFromPipelineByPropertyName=$True,
HelpMessage=’File Extension for Logfiles’)]
[STRING[]]$Extension=".log"
)
Begin {}
Process {
WRITE-DEBUG “`$Folder: $Folder[0]”
WRITE-DEBUG “`$Preface: $Preface[0]”
WRITE-DEBUG “`$Extension: $Extension[0]”
# GET the Current Date for our Logfile
$Today=GET-DATE
WRITE-DEBUG “`$Today: $Today”
# Extract the Date removing the “/”
$Date=$Today.toshortdatestring().Replace(“/”,””)
WRITE-DEBUG “`$Date: $Date”
# Extract the Time removing the “:”
$Time=$Today.tostring(“HH:mm:ss”).Replace(“:”,”“)
WRITE-DEBUG “`$Time: $Time”
# Build our Filename
$Logfilename=$Folder[0]+"\"+$Preface[0]+”-“+$Date+”-“+$Time+$Extension[0]
WRITE-DEBUG “`$Logfilename: $Logfilename”
# Test and ensure file does not already exist
IF (TEST-PATH -path $Logfilename)
{ WRITE-ERROR –message “Error: $Logfilename exists.” –category ‘WriteError’
# If file exists, return a status of Boolean $False for Unsuccessful
RETURN $Logfilename,$FALSE }
ELSE
{
# Create logfile
NEW-ITEM –Type File -path $Logfilename -Force | OUT-NULL
WRITE-DEBUG “$Logfilename successfully created”
# Return the Full path and filename if successful
RETURN $Logfilename,$TRUE
}
End {}
}
}
At this point, please save this as ADDLOG.PS1 and execute it to reload the cmdlet into memory. Then try the following cmdlets:
-
GET-HELP ADD-LOGFILE –examples
-
ADD-LOGFILE C:\MyFolder
-
ADD-LOGFILE –Extension .FIL
-
ADD-LOGFILE –whatif
As you can see, although this particular cmdlet has a very simple function, it is not difficult to leverage many of the features in Windows PowerShell to extend its abilities. It feels very much like a real cmdlet, and that is because it is a real cmdlet.
~Sean
Thank you, Sean. Whew! This is some good stuff. Join me tomorrow when we will see Sean bring this thing to a conclusion. It is great! It is awesome! It is downright cool!!
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