In order to provide clean and consistent code, please follow the style guidelines listed below when contributing to the repository.
Use descriptive, clear, and full names for all variables, parameters, and functions. All names must be at least more than 2 characters. No abbreviations should be used.
Bad:
$vmh = Get-VMHost
Bad:
$sixty = 60
Bad:
function Get-Something {
...
}
Bad:
function Set-VMHost {
param (
$myVMH
)
...
}
Good:
$vmHost = Get-VMHost
Good:
$secondsInAMinute = 60
Good:
function New-DNSConfig {
...
}
Good:
function Update-DNSConfig {
param (
[VMware.Vim.HostNetworkSystem] $NetworkSystem
)
...
}
Use named parameters for function and cmdlet calls rather than positional parameters. Named parameters help other developers who are unfamiliar with your code to better understand it.
When calling a function with many long parameters, use parameter splatting. If splatting is used, then all the parameters should be in the splat. More help on splatting can be found in the article About Splatting.
Bad:
Not using named parameters.
Get-VMHost MyVM
Good:
Get-VMHost -Name MyVM
Arrays should be written in one of the following formats.
If an array is declared on a single line, then there should be a single space between each element in the array. If arrays written on a single line tend to be long, please consider using one of the alternative ways of writing the array.
Bad:
Array elements are not format consistently.
$ntpServer = @( 'ntp server 1', `
'ntp server 2', `
'ntp server 3'
)
Bad:
There are no single space beetween the elements in the array.
$ntpServer = @('ntp server 1','ntp server 2','ntp server 3')
Bad:
There are multiple array elements on the same row.
$ntpServer = @(
'ntp server 1', 'ntp server 2', `
'ntp server 3', `
'ntp server 4', 'ntp server 5'
)
Good:
$ntpServer = @('ntp server 1', 'ntp server 2', 'ntp server 3')
Good:
$ntpServer = @(
'ntp server 1',
'ntp server 2',
'ntp server 3'
)
Good:
$ntpServer = @(
'ntp server 1'
'ntp server 2'
'ntp server 3'
'ntp server 4'
'ntp server 5'
)
Hashtables and Objects should be written in the following format. Each property should be on its own line indented once.
Bad:
$performanceIntervalArgs = @{ Key = $currentPerformanceInterval.Key
Name = $currentPerformanceInterval.Name
Enabled = $this.SpecifiedOrCurrentValue($this.Enabled, $currentPerformanceInterval.Enabled)
Level = $this.SpecifiedOrCurrentValue($this.Level, $currentPerformanceInterval.Level)
SamplingPeriod = $this.SpecifiedOrCurrentValue($this.IntervalMinutes * $this.SecondsInAMinute, $currentPerformanceInterval.SamplingPeriod)
Length = $this.SpecifiedOrCurrentValue($this.PeriodLength * $this.Period, $currentPerformanceInterval.Length)
}
Good:
$performanceIntervalArgs = @{
Key = $currentPerformanceInterval.Key
Name = $currentPerformanceInterval.Name
Enabled = $this.SpecifiedOrCurrentValue($this.Enabled, $currentPerformanceInterval.Enabled)
Level = $this.SpecifiedOrCurrentValue($this.Level, $currentPerformanceInterval.Level)
SamplingPeriod = $this.SpecifiedOrCurrentValue($this.IntervalMinutes * $this.SecondsInAMinute, $currentPerformanceInterval.SamplingPeriod)
Length = $this.SpecifiedOrCurrentValue($this.PeriodLength * $this.Period, $currentPerformanceInterval.Length)
}
Single quotes should always be used to delimit string literals wherever possible. Double quoted string literals may only be used when it contains ($) expressions that need to be evaluated.
Bad:
$vmhost = "VMHost with name was not found."
Good:
$vmhost = 'VMHost with name was not found.'
Good:
$vmhost = 'VMHost with name $($this.Name) was not found.'
There should not be any commented-out code in checked-in files. The first letter of the comment should be capitalized.
Single line comments should be on their own line and start with a single pound-sign followed by a single space. The comment should be indented the same amount as the following line of code.
Comments that are more than one line should use the <# #>
format rather than the single pound-sign.
The opening and closing brackets should be on their own lines.
The brackets should be indented the same amount as the following line of code.
Bad:
<#
.DESCRIPTION
Name of the Server we are trying to connect to. The Server can be a vCenter or ESXi.
#>
[DscProperty(Key)]
[string] $Server
Bad:
# Empty array specified as desired, but current is not an empty array, so update VMHost NTP Server.
return $true
Good:
<#
.DESCRIPTION
Name of the Server we are trying to connect to. The Server can be a vCenter or ESXi.
#>
[DscProperty(Key)]
[string] $Server
Good:
# Empty array specified as desired, but current is not an empty array, so update VMHost NTP Server.
return $true
PowerShell reserved Keywords should be in all lower case and should be immediately followed by a space if there is non-whitespace characters following (for example, an open brace).
The following is the current list of PowerShell reserved keywords in PowerShell 5.1:
begin, break, catch, class, continue, data, define do, dynamicparam, else,
elseif, end, enum, exit, filter, finally, for, foreach, from, function
hidden, if, in, inlinescript, param, process, return, static, switch,
throw, trap, try, until, using, var, while
This list may change in newer versions of PowerShell.
The latest list of PowerShell reserved keywords can also be found on this page.
Bad:
# Missing space after keyword and before open bracket
foreach($item in $list)
Bad:
# Capital letters in keyword
TRY
Bad:
# Capital letters in 'in' and 'foreach' keyword
ForEach ($item In $list)
Bad:
try
{
# Do some work
}
Good:
foreach ($item in $list)
Good:
try {
# Do some work
}
Backticks should always be directly followed by a newline.
All files must end with a newline, see StackOverflow.
Code should not contain more than two consecutive newlines unless they are contained in a here-string.
Bad:
function Get-VMHost {
Write-Verbose -Message 'Getting VMHost'
return $vmHost
}
Good:
function Get-VMHost {
Write-Verbose -Message 'Getting VMHost'
return $vmHost
}
Each closing curly brace ending a function, conditional block, loop, etc. should be followed by exactly two newlines unless it is directly followed by another closing brace. If the closing brace is followed by another closing brace or continues a conditional or switch block, there should be only one newline after the closing brace.
Bad:
function Get-VMHost {
Write-Verbose -Message 'Getting VMHost'
return $vmHost
} Get-VMHost
Bad:
function Get-VMHost {
Write-Verbose -Message 'Getting VMHost'
if ($myBoolean) {
return $vmHost
}
else {
return 0
}
}
Get-VMHost
Good:
function Get-VMHost {
Write-Verbose -Message 'Getting VMHost'
if ($myBoolean) {
return $vmHost
}
else {
return 0
}
}
Get-VMHost
If you must declare a variable type, type declarations should be separated from the variable name by a single space.
Bad:
function Get-VMHost {
[CmdletBinding()]
param ()
[VMHost]$vmHost = <VMHost>
}
Good:
function Get-VMHost {
[CmdletBinding()]
param ()
[VMHost] $vmHost = <VMHost>
}
There should be one blank space on either side of all operators.
Bad:
function Get-Number {
[CmdletBinding()]
param ()
$number=2+4-5*9/6
}
Bad:
function Get-Message {
[CmdletBinding()]
param ()
if ('example'-eq'example'-or'magic') {
Write-Verbose -Message 'Example found.'
}
}
Good:
function Get-Number {
[CmdletBinding()]
param ()
$number = 2 + 4 - 5 * 9 / 6
}
Good:
function Get-Message {
[CmdletBinding()]
param ()
if ('example' -eq 'example' -or 'magic') {
Write-Verbose -Message 'Example found.'
}
}
If a keyword is followed by a parenthesis, there should be single space between the keyword and the parenthesis.
Bad:
function Get-Message {
[CmdletBinding()]
param ()
if('example' -eq 'example' -or 'magic'){
Write-Verbose -Message 'Example found.'
}
foreach($example in $examples){
Write-Verbose -Message $example
}
}
Good:
function Get-Message {
[CmdletBinding()]
param ()
if ('example' -eq 'example' -or 'magic') {
Write-Verbose -Message 'Example found.'
}
foreach ($example in $examples) {
Write-Verbose -Message $example
}
}
Function names must use PascalCase. This means that each concatenated word is capitalized.
Bad:
function get-vmhost {
# ...
}
Good:
function Get-VMHost {
# ...
}
All function names must follow the standard PowerShell Verb-Noun format.
Bad:
function VMHostGetter {
# ...
}
Good:
function Get-VMHost {
# ...
}
All function names must use approved verbs.
Bad:
function Normalize-String {
# ...
}
Good:
function ConvertTo-NormalizedString {
# ...
}
All functions should have comment-based help with the correct syntax directly above the function. Comment-help should include at least the SYNOPSIS section and a PARAMETER section for each parameter.
Bad:
# Creates an event
function New-Event {
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Message,
[Parameter()]
[ValidateSet('operational', 'debug', 'analytic')]
[String]
$Channel = 'operational'
)
# Implementation...
}
Good:
<#
.SYNOPSIS
Creates an event
.PARAMETER Message
Message to write
.PARAMETER Channel
Channel where message should be stored
.EXAMPLE
New-Event -Message 'Attempting to connect to server' -Channel 'debug'
#>
function New-Event {
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Message,
[Parameter()]
[ValidateSet('operational', 'debug', 'analytic')]
[String]
$Channel = 'operational'
)
# Implementation
}
All parameters must use PascalCase. This means that each concatenated word is capitalized.
Bad:
function Get-VMHost {
[CmdletBinding()]
param (
$VMHOSTNAME
)
}
Bad:
function Get-VMHost {
[CmdletBinding()]
param (
$vmhost
)
}
Good:
function Get-VMHost {
[CmdletBinding()]
param (
[Parameter()]
$VMHost
)
}
Variable names should use camelCase.
Bad:
function Write-Log {
$VerboseMessage = 'New log message'
Write-Verbose $VerboseMessage
}
Bad:
function Write-Log {
$verbosemessage = 'New log message'
Write-Verbose $verbosemessage
}
Good:
function Write-Log {
$verboseMessage = 'New log message'
Write-Verbose $verboseMessage
}
Script, environment, and global variables must always include their scope in the variable name unless the 'using' scope is needed. The script and global scope specifications should be all in lowercase. Script and global variable names following the scope should use camelCase.
Bad:
$fileCount = 0
$GLOBAL:MYRESOURCENAME = 'MyResource'
function New-File {
$fileCount++
Write-Verbose -Message "Adding file to $MYRESOURCENAME to $ENV:COMPUTERNAME."
}
Good:
$script:fileCount = 0
$global:myResourceName = 'MyResource'
function New-File {
$script:fileCount++
Write-Verbose -Message "Adding file to $global:myResourceName to $env:computerName."
}
Using hardcoded computer names exposes sensitive information on your machine. Use a parameter or environment variable instead if a computer name is necessary.
Bad:
Invoke-Command -Port 0 -ComputerName 'hardcodedName'
Good:
Invoke-Command -Port 0 -ComputerName $env:computerName
Empty catch blocks are not necessary. Most errors should be thrown or at least acted upon in some way. If you really don't want an error to be thrown or logged at all, use the ErrorAction parameter with the SilentlyContinue value instead.
Bad:
try {
Get-Command -Name Invoke-NotACommand
}
catch {}
Good:
Get-Command -Name Invoke-NotACommand -ErrorAction SilentlyContinue
When comparing a value to $null
, $null
should be on the left side of the comparison.
This is due to an issue in PowerShell.
If $null
is on the right side of the comparison and the value you are comparing it against happens to be a collection, PowerShell will return true if the collection contains $null
rather than if the entire collection actually is $null
.
Even if you are sure your variable will never be a collection, for consistency, please ensure that $null
is on the left side of all comparisons.
Bad:
if ($myArray -eq $null) {
Remove-AllItems
}
Good:
if ($null -eq $myArray) {
Remove-AllItems
}
Avoid using global variables whenever possible. These variables can be edited by any other script that ran before your script or is running at the same time as your script. Use them only with extreme caution, and try to use parameters or script/local variables instead.
Bad:
$global:configurationName = 'MyConfigurationName'
...
Set-MyConfiguration -ConfigurationName $global:configurationName
Good:
$script:configurationName = 'MyConfigurationName'
...
Set-MyConfiguration -ConfigurationName $script:configurationName
Don't declare a local or script variable if you're not going to use it. This creates excess code that isn't needed
PSCredentials are more secure than using plaintext username and passwords.
Bad:
function Get-Settings {
param (
[String]
$Username
[String]
$Password
)
...
}
Good:
function Get-Settings {
param (
[PSCredential]
[Credential()]
$UserCredential
)
}
Pester assertions should all start with capital letters. This makes the code easier to read.
Bad:
it 'Should return something' {
get-targetresource @testParameters | should -be 'something'
}
Good:
It 'Should return something' {
Get-TargetResource @testParameters | Should -Be 'something'
}