20

Are there any well-defined conventions when programming in PowerShell?

For example, in scripts which are to be maintained long-term, do we need to:

  • Use the real cmdlet name or alias?
  • Specify the cmdlet parameter name in full or only partially (dir -Recurse versus dir -r)
  • When specifying string arguments for cmdlets do you enclose them in quotes (New-Object 'System.Int32' versus New-Object System.Int32
  • When writing functions and filters do you specify the types of parameters?
  • Do you write cmdlets in the (official) correct case?
  • For keywords like BEGIN...PROCESS...END do you write them in uppercase only?

It seems that MSDN lack coding conventions document for PowerShell, while such document exist for example for C#.

3

4 Answers 4

9

@Robert Harvey referenced some good formal links. By way of a less formal document, my thoughts would be:

Use the real cmdlet name or alias?

Only use the alias if it is more clear than the full name. For example, I think most people would find dir or ls more clear in a script than Get-ChildItem based on previous experience (e.g. basically anyone writing a PowerShell script has one of those two many times in either DOS batch scripts or Unix scripting).

Specify the cmdlet parameter name in full or only partially (dir -Recurse versus dir -r)

In a script, I would fully spell out the name because (unlike the above example) I cannot think of a time where the shorter switch would actually be more clear than spelling it out. Shorter switch names are to save typing. At a command line, this is imperative. In a script, the extra keystrokes are well worth it for readability and maintainability.

When specifying string arguments for cmdlets do you enclose them in quotes (New-Object 'System.Int32' versus New-Object System.Int32

Enclosing string arguments in quotes seems much more clear when reading through the code, so I would include them.

When writing functions and filters do you specify the types of parameters?

Only when there is a need to do so to resolve ambiguity for the interpreter (which does happen). If you are going to try and put types on everything, you might as well go and write C# command line applications (which isn't always a bad thing, but it negates the time savings you get by scripting).

Do you write cmdlets in the (official) correct case?

You should. I usually do. When hurried I have been known to be a little lax on case since it does not syntactically matter.

For keywords like BEGIN...PROCESS...END do you write them in uppercase only?

No. This is not FORTRAN. I think most people find begin or Begin more readable than BEGIN. There is a reason we associate all caps with shouting online and shouting the most mundane portions of the program hinders readability by drawing one's attention to the parts that matter the least.

The guiding principal should be readability. Scripts, by their very nature as quick and dirty programs, veer towards write-only code. Your every decision should be made to ensure that you and your team can still understand the script in six months. Try to take yourself out of your own shoes when looking at your code and ask this question: "if I had started this job a week ago (and so was not really indoctrinated into the general culture) would I find the way this is written illuminating or confusing?"

2

Microsoft has written and published a very good set of Cmdlet Development Guidelines

Excerpt:

The topics in this section provide development guidelines that you can use to produce well-formed cmdlets. By leveraging the common functionality provided by the Windows PowerShell runtime and by following these guidelines, you can develop robust cmdlets with minimal effort and provide the user with a consistent experience. Additionally, you will reduce the test burden because common functionality does not require retesting.

In This Section

These guidelines are not limited to any language (they do not mention a language), and are perfectly applicable when writing Cmdlets in PowerShell.

Using these guidelines will help you write clear, discoverable, usable and reuseable Cmdlets. I find after creating several PowerShell modules following these guidelines is not hard, and helped me become a better PowerShell developer. That skill is directly usable when writing simple scripts as well.

2
  • 1
    These seem more about how to write cmdlets, rather than how to write PowerShell. Commented Jan 25, 2015 at 23:41
  • @PhilipKendall they do indeed. This may not answer the complete question, but i do belief this adds value to the question. Note that you can write your Cmdlets perfectly in pure PowerShell, and that these guidelines really help with that as well. If you can write a good Cmdlet in PowerShell, than you can write good PowerShell scripts as well.
    – oɔɯǝɹ
    Commented Jan 25, 2015 at 23:44
1

As a second answer; you can use the PSScriptAnalyzer module to validate your code.

Invoke-ScriptAnalyzer -Path .

It is based on code analysis, using a ruleset. It will validate code design, and will help you detect many little issues in your code.

We incorporated it in our builds (we use builds and a private repository for modules), to catch design and quality issues.

If you're interested, this module also contains a PowerShell code formatter (which can use multiple styles), so you can use that to standardize code layout as well.

0

The documents in @oɔɯǝɹ's answer are a good, if somewhat tangential source.

If you use Visual Studio Code, which is planned to replace the aging PowerShell ISE, and then install the VS Code PowerShell extension, that includes several formatting options which was at least partially based on the Unofficial PowerShell Best Practices and Style Guide. Both VS Code and the PowerShell extension are managed by Microsoft, so it's about as official as an unofficial guide can be.

I don't agree with everything they state. For example, I come from PHP, Java, C#, and SQL where semicolons are expected if not required. Code looks wrong to me without them, so I include them. If there were a #requires SemicolonTerminator I'd enable it on most of my scripts so I don't have to worry about whitespace breaking a line. I hate escaping carriage returns and other VB-isms.

The rest of these are my opinion:

Use the real cmdlet name or alias?

Be unambiguous. Never use an alias in a saved script; even a default alias. There's nothing stopping a user from changing default aliases. It's safer to assume they're not immutable.

Specify the cmdlet parameter name in full or only partially (dir -Recurse versus dir -r)

Again, be unambiguous. Full parameter names have the best forward compatibility. -r might be unambiguous today, but there's nothing stopping future versions of a command from introducing new parameters. You're going to be using an IDE (either ISE or VS Code). Hit Ctrl+Space and autocomplete that parameter.

Note that ls -r is ambiguous. -ReadOnly is another parameter of Get-ChildItem.

When specifying string arguments for cmdlets do you enclose them in quotes (New-Object 'System.Int32' versus New-Object System.Int32

In general, quotes should only be used when necessary (e.g., New-Object -TypeName 'System.Collections.Generic.HashSet[System.Int32]'. Use single quotes when you can, and only double quotes when you need to encapsulate single quotes or need to embed variables.

When writing functions and filters do you specify the types of parameters?

I typically do, unless I specifically need to accept a wide variety of types with the same parameter and don't want to write individual parameter sets.

Do you write cmdlets in the (official) correct case?

Pascal case. Yes.

For keywords like BEGIN...PROCESS...END do you write them in uppercase only?

I've seen statements, operators, and language constructs as Begin, If, ForEach, -NotIn as well as begin, if, foreach, -notin. Personally, I prefer lower case and leave commands as Pascal case, but they're both equally common.

Others:

  • Always specify parameters. Don't rely on positional order. New-Object -TypeName System.Int32 over New-Object System.Int32. I don't know if that's agreed upon, but, again, it seems to support the general idea of "be unambiguous".

  • If I'm writing a module, I use standard verbs indicated by Get-Verb. This list is extremely narrow, however, so stand-alone script names for scripts that only I myself will run often don't. The problem with the generic verb list is that it tends towards into Get-ScriptForSpecificPurposeNoNotThatOneTheOtherOne.ps1. If I'm writing a script that extracts certain pages from a PDF file, I'm not calling it Get-ExtractedAccountPDFPages.ps1. I'm calling it Extract-AccountPDFPages.ps1. I'm not concerned about the discoverability of a script that runs as a program itself and isn't intended to be modular by it's very nature.

  • Break the rules when it's more readable, more concrete, or more maintainable.

Not the answer you're looking for? Browse other questions tagged or ask your own question.