For the past few years, I’ve picked up a several best practices for PowerShell scripting. Some of them are “borrowed” from Ed Wilson (aka the Microsoft Scripting Guy), Don Jones, and other PowerShell MVPs and PFEs @ Microsoft.
Note: For more PowerShell best practices, check the PowerShellPracticeAndStyle github repository
- Start your scripts with a standard set of comments (name, date, author, purpose and keywords) to easily find them later.
- Add comments as much as possible, but not too much.
- Use the #Requires tag for the minimum version of Windows PowerShell required, required Modules, PSSnapin or Administrative rights.
- Use the Set-StrictMode -Version Latest command to ensure that you cannot reference things such as uninitialized variables and non-existent properties of an object.
- Use simple but meaningful variable names. camelCase is the best practice. (e.g. $serviceName or $counterName, and not $s and $c). Note that this is for variables inside a script or function, not for parameter names (see #17 for parameter names best practices).
- Place user-defined variables at the top of script. It makes it easier for you or anyone making changes to those script variables.
- Use code signing (and the RemoteSigned or AllSigned execution policy).
- Don't use aliases in scripts. Use the full cmdlet name with its named parameters.
- Avoid using backticks, they are easy to miss since they might look like dirt on the screen. Instead, use the pipeline (|) character where appropriate, or even splatting the parameters to the cmdlet.
- "Filter left, format right".
- Add the .exe extension to external commands and applications (e.g. there is a big difference between sc and sc.exe).
- Don’t turn off pipeline errors ($ErrorActionPreference = "SilentlyContinue"). Implement structured error handling by using Try+Catch+Finally (or Trap) to handle errors.
- Do not "pollute" the Windows PowerShell environment by changing preference variables globally (e.g. $ConfirmPreference, $WhatIfPreference, etc.).
- Use cmdletBinding and add support for the -WhatIf, -Verbose and -Debug parameters.
- Use Advanced Functions.
- Use the Verb-Noun naming convention for your functions and filters. When picking out verbs, always use standard verbs. Use Get-Verb to see what verbs are available.
- Use standard parameter naming (e.g. ComputerName and not Machine or Server), and set them a default value if relevant (e.g. $ComputerName = $ENV:ComputerName).
- A function should do one thing, and do it well.
- A function should always return an object or array of objects, not formatted text.
- Avoid using the Return keyword. Functions automatically return output to the calling process through the pipeline.
Avoid using Write-Host. It writes to the host, not the pipeline.Prefer using Write-Output over using Write-Host. Write-Host writes to the host, not the pipeline.
- Use comment-based help. The minimum items to add are the Synopsis, Description, and Example nodes.
- Use Test-Connection (with the -Quiet switch) to ensure a computer is online prior to connecting to it.
- Make sure your script is lined up, indented properly, and easy to read. If you can read and understand your script, you will simplify your debugging process.
- Keep your script independent from the place you run it (Use $myInvocation.MyCommand.Path or $PSScriptRoot for PowerShell 3.0 and above).
- Make sure you test your functions and scripts in a clean environment with no dependencies on profiles, admin rights, and versions to ensure compatibility.
- Test scripts in test environment before they are released to production.
- Re-use scripts (Package modules, create a script repository).
- Implement some processes around script lifecycle (change process)
- Who can request the creation of scripts?
- Who is responsible for writing the scripts?
- Who is responsible for maintaining the scripts?
- Who is responsible for reviewing (quality control) the scripts?
- Follow a simple but organized script flow:
- #Requires comments
- Define your params
- Create your functions
- Setup any variables
- Run your code
- Comment based help
If you have any other best practice you’d like to share, use the comments box below. I’ll add it to the list and mention your name too (if you want).