PowerShell Best Practices: Simple Functions

PowerShell Best Practices: Simple Functions

  • Comments 10
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, talks about Windows PowerShell best practices related to simple functions.

Microsoft Scripting Guy, Ed Wilson, is here. The first time I saw this tea, I thought, "Dude, what an extravagance." I mean, a fine cup of Darjeeling tea is a true treat. It is mellow, light, and it is lightly aromatic. So why cover up that fine tea with bergamot and make a Darjeeling Earl Grey tea? Well for one thing, it is so wonderful, that it becomes addictive. During my recent trip to Europe, I stopped at nearly a dozen tea shops, and of course, I came back with a couple of very nice bags of Darjeeling Earl Grey tea. This morning I brewed a pot, and I added a little lavender, cinnamon stick, lemon peel, and rock sugar (which I also brought back from Europe). A couple squares of 90 percent cocoa chocolate and a handful of macadamia nuts completes my morning snack.

Note  If you have not yet seen it, you should check out the new community Windows PowerShell video, Scripting Cmdlet Style. It is inspirational and fun. See how many MVPs you can identify, how many Windows PowerShell team members you see, and if you can spot the Microsoft Scripting Guy. Filmed at TechEd 2014 in Dallas Texas, it is a tribute to the Windows PowerShell community and to the great technology we love.

Image of booth

A simple Windows PowerShell function consists of three parts: the function keyword, the name of the function, and a script block. In fact, I can create a function in the Windows PowerShell console on a single line, for example:

function demo {"hello $input"}

I can now pipe input to the demo function. The command and its output are shown in the following image:

Image of command output

In reality, I do not do this. Whereas it is theoretically possible to create functions directly inside the Windows PowerShell console, unless you happen to be Bruce Payette, I simply do not think it is a very practical solution. When I write simple functions, I use the Windows PowerShell ISE or a commercial script editor such as PowerShell Studio 2014. In fact, I use the Windows PowerShell ISE as a more advanced and more customizable Windows PowerShell environment.

Here are the best practices I follow when I write simple functions:

1. Write simple functions in a script editor, such as the Windows PowerShell ISE.

2. Use the Verb-Noun naming convention. Although it is possible to use very nondescript names (such as a, b, c), I prefer to use Verb-Noun. It does not hurt anything, and it provides a good foundation if I decide to turn the function into an advanced function at a later time.

3. I like to use $input and pipe input to a simple function. This makes things really easy, and I do not have to fool with things like parameters.

4. I do not like to write one-line functions, no matter how compact they may be. They are a bit hard to read. If they are really simple, I put the function keyword and the Verb-Noun name on one line, and the script block on a second line.

5. I like to include a space after the opening of the script block and before the closing of the script block, for example:

{ “hello $input” }

This type of syntax will make it easier when I decide I want to add more stuff to the script block.

6. I like to organize my functions in the order that they will appear in the script. But I do not get too carried away with this, and quite often the order ends up jumbled.

7. Use the regions in the Windows PowerShell ISE. To do this, I begin with the #region tag and end with the #endregion tag. This permits collapsing the region later to facilitate development.

8. A good function should do one thing, and do it well.

9. A good function should be flexible and accept different types of input.

10. A good function should have one way in and one way out.

11. A good function should always return an object, and not formatted text.

12. A good function avoids using things like Write-Host that will not be captured in the output stream.

13. A good function does not pollute the Windows PowerShell environment.

14. Anything that is set in a function should be unset when the function completes running. The best way to do this is to capture the current value and store in a variable. Then when the function is finished, set the value back to the initial value that is stored in the variable. An example of this is changing the value of $ErrorActionPrefrence.

15. When you are finished using your function, you may want to remove the function from the Function drive. An example of this is:

Get-Item Function:\demo | Remove-Item

16. If you have made a substantial number of changes to your running Windows PowerShell environment, the easiest way to clean things up is simply to close the Windows PowerShell ISE or console. To do this you can type exit at the Windows PowerShell prompt.

17. You should think about adding some rudimentary input validation to even a simple function. For example, if the function accepts a computer name for input, you might decide to use Test-Connection to ensure the computer is online prior to running the rest of the function. Or you could have an array of permissible computer names, and ensure that the input name is contained in the array.

18. If the function is supposed to do something, and it might fail, you should include script to clean up if it does fail. One easy way to do this is if your provider supports transactions.

19. Even for a simple function, you should include at least a comment or two about how to use the function. It does not have to be full-blown comment-based Help, but at least include a sample syntax and maybe something about the purpose of the function.

20. I generally like to include a date written in my function, even if I do not add versioning. This give some hint of the version of the function should I run across a different function with the same name.

21. In general, if you are following the Verb-Noun construction, it is quite likely that you will run into naming conflict between different functions. For example, I have over a dozen Get-Bios functions on my computer that I have written over the years. This is the reason for following at least rule #20, and for this rule. It is a good idea to include a major.minor version number in your script, for example: 1.0 for first version of script, 2.0 for a rewrite that added new functionality, and 2.1 for a minor revision that corrected a flaw or cleaned up the script a bit.

22. Keep in mind that these are simple functions, and don’t get too carried away. But if you find that the function is becoming really useful, think about moving it to an advanced function.

That is all there is to using simple functions with Windows PowerShell. Best Practices Week will continue tomorrow when I will talk about advanced functions.

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

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Consider the following in reference to statement about setting things like in #14

    PS C:\scripts> $erroractionpreference
    PS C:\scripts> function test{ $erroractionprefference='SilentlyContinue' }
    PS C:\scripts> test
    PS C:\scripts> $erroractionpreference
    PS C:\scripts>

    Note that #14 is not really necessary due to scope.

  • Lots of good tips, but I still want to pick on three of them ;)

    As jrv said, #14 only applies to changes to GLOBAL scope (e.g. environment variables)

    Also, regarding #3, beware of $input, because it changes if you ever add a process block. Once you have a process block, $input has no value in the end block. Also, I think that #9 (flexibility of input) and #17 (input validation) conflict with #3 too: Once you're doing input validation, it's probably easier (and more forward thinking) to write a param block, which goes a long way toward flexibility of input and #19 (documenting how to use it).

    Finally, I don't think #7 is really a "best practice" -- although it might be a good tip for ISE users, ISE supports code folding on curly braces now, so there's rarely a need to wrap things in regions in a simple function.

  • thank you

  • Nice one