PowerShell Pipeline
Considerations When Writing a PowerShell Function
Here's how to make the jump from simple lines of code to something that's a lot more useful.
After reading countless blogs online, purging through hundreds of pages of books, you feel comfortable enough to begin working with PowerShell and start knocking out one-liners like they are going out of style. The next step in your process is to build out a function to make some of your code snippets more reusable that can be shared out with your coworkers or with the PowerShell community.
But where do you begin? A lot of times I see functions which are built that miss out on many things that could take it from a simple function to a superstar function that can really be an amazing part of your script library. What I aim to do here is to help you by providing some tips on what you should do when you build a function to make it the best that it can be.
Do One Thing and Do It Great
When you write a function, it should only serve a single purpose. If it is supposed to query something, it just queries something and returns the result back as an object to the console. It should not query something and then set something nor should it query something and then write it to a file. If you want to do that, write a script that includes not only your function, but uses it along with another function or cmdlet that writes it out to a file. The idea is to keep the scope of the function limited to a single thing so you can make it easier to maintain. If you need multiple functions to accomplish your goal, then add those into a module.
Proper Naming of a Function
Take a look at all of the core PowerShell cmdlets and you will noticed something right away: all of them follow a naming convention of Verb-SingularNoun. As important as this is, you also need to be aware of the current approved verbs in PowerShell. This isn't a strict thing, meaning PowerShell won't punish you if you use a verb that isn't considered approved. But if you build a module, it will warn you upon import that some of the functions are not following the approved verbs. You can find a list of approved verbs by running the Get-Verb cmdlet.
Use Proper Parameter Names
Similar to the previous section, the use of readable parameters can make all of the world when someone is trying to run code. Aliases are fine as an alternate parameter, but shouldn't replace a full parameter name. Using parameters which are already common in the core PowerShell cmdlets such as Computername should always be used in place of parameters such as Computer, CN, Server. Also like function names, you should avoid using a plural if at all possible.
Add Help and Examples to Your Function
When you were first starting out with PowerShell, I'm sure that much like myself, you were looking at the help included with each cmdlet using Get-Help. Well, here is your chance to do the same thing for someone else that uses your code by writing help which covers what the function actually does, what each parameter means and finally some useful examples so others know how to actually use the function. Without writing help for the function, your function may be ignored as it could be hard to know just how to use it.
If It Makes a Change, Then It Should Support Process
How often have you run a cmdlet that makes a change and you just wanted to know if it would work in the way that you think it would and decided to make use of the –WhatIf parameter? And how many times has it actually saved you from potential disaster or a resume generating event (RGE)? The rule of thumb here is that if you write a function that makes a change of any kind, regardless of how trivial it seems, you need to take the time to write in some code that allows the use of –WhatIf. Some great examples of doing this can be found here.
Make use of Verbose and Debug Parameters Within the Function
The best way to help troubleshoot a script issue or allow a user of the code to see what is happening is within the Write-Verbose and Write-Debug cmdlets. The trick to this is that even though you have those cmdlets embedded within your function, they are not automatically used unless you have [cmdletbinding()] added to your function.
[cmdletbinding()]
Param()
Once you have that added (also along with Param() for your parameters), you then open up the common parameters such as –Verbose and –Debug. One side note to this is that –Debug has an interesting side effect of setting the $DebugPreference to 'Inquire' which prompts you for input with each call to Write-Debug. To get around this little thing, you can look for –Debug being used and then set the $DebugPreference to 'Continue.'
If ($PSBoundParameters.ContainsKey('Debug')) {
$DebugPreference = 'Continue'
}
If It Needs Pipeline Support, then Support It
A function that expects pipeline support needs to do more than just say it. You have to supply the proper parameter attribute depending on its needs. If it needs to just accept it by value based on its object type or if it can accepts it by the name of one of its properties. That is just the first step in the process and by process I mean that you also have to have at a minimum, a Process block as this is the key component to allowing pipeline data to be processed correctly. More information about providing proper pipeline support for functions can be found here to use.
With that, you can now take these considerations into action and work them into your function building process and make them great! Feel free to add comments below on things that you believe are important in building a function.
About the Author
Boe Prox is a Microsoft MVP in Windows PowerShell and a Senior Windows System Administrator. He has worked in the IT field since 2003, and he supports a variety of different platforms. He is a contributing author in PowerShell Deep Dives with chapters about WSUS and TCP communication. He is a moderator on the Hey, Scripting Guy! forum, and he has been a judge for the Scripting Games. He has presented talks on the topics of WSUS and PowerShell as well as runspaces to PowerShell user groups. He is an Honorary Scripting Guy, and he has submitted a number of posts as a to Microsoft's Hey, Scripting Guy! He also has a number of open source projects available on Codeplex and GitHub. His personal blog is at http://learn-powershell.net.