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.