In order to provide clean and consistent code, please follow the style guidelines listed below when contributing to any DSC Resource Kit repositories.
- Markdown Files
- General
- Whitespace
- Indentation
- No Trailing Whitespace After Backticks
- Newline at End of File
- Newline Character Encoding
- No More Than Two Consecutive Newlines
- One Newline Before Braces
- One Newline After Opening Brace
- Two Newlines After Closing Brace
- One Space Between Type and Variable Name
- One Space on Either Side of Operators
- One Space Between Keyword and Parenthesis
- Functions
- Parameters
- Variables
- Best Practices
If a paragraph includes more than one sentence, end each sentence with a newline.
GitHub will still render the sentences as a single paragraph, but the readability of git diff
will be greatly improved.
Make sure all files are encoded using UTF-8, except mof files which should be encoded using ASCII.
You can use ConvertTo-UTF8
and ConvertTo-ASCII
to convert a file to UTF-8 or ASCII.
Each line should have less than 100 characters.
Bad:
powershell
$reallyLongString = '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'
**Good:**
```powershell```
$reallyLongString = '123456789012345678901234567890123456789012345678901234567890' + `
'123456789012345678901234567890123456789012345678901234567890'
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:
$r = Get-RdsHost
Bad:
$frtytw = 42
Bad:
function Get-Thing
{
...
}
Bad:
function Set-ServerName
{
param
(
$mySTU
)
...
}
Good:
$remoteDesktopSessionHost = Get-RemoteDesktopSessionHost
Good:
$fileCharacterLimit = 42
Good:
function Get-ArchiveFileHandle
{
...
}
Good:
function Set-ServerName
{
param
(
$myServerToUse
)
...
}
When calling a function with many parameters, if the line exceeds the line character limit, use parameter splatting. More help on splatting can be found using the command:
Get-Help -Name 'About_Splatting'
Make sure hashtable parameters are still properly formatted with multiple lines and the proper indentation.
Bad:
$superLongVariableName = Get-MySuperLongVariablePlease -MySuperLongHashtableParameter @{ MySuperLongKey1 = 'MySuperLongValue1'; MySuperLongKey2 = 'MySuperLongValue2' } -MySuperLongStringParameter '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' -Verbose
Good:
$getMySuperLongVariablePleaseParams = @{
MySuperLongHashtableParameter = @{
mySuperLongKey1 = 'MySuperLongValue1'
mySuperLongKey2 = 'MySuperLongValue2'
}
MySuperLongStringParameter = '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'
Verbose = $true
}
$superLongVariableName = Get-MySuperLongVariablePlease @getMySuperLongVariablePleaseParams
Arrays should be written in the following format. Arrays should be writen on one line unless they exceed the line character limit. There should be a single space between each element in the array. Hashtables should not be declared inside an array.
Bad:
$array = @( 'one', `
'two', `
'three'
)
Good:
$hashtable = @{
Key = "Value"
}
$array = @( 'one', 'two', 'three', $hashtable )
Hashtables and Objects should be written in the following format. Each property should be on its own line indented once.
Bad:
$hashtable = @{Key1 = 'Value1';Key2 = 2;Key3 = '3'}
Bad:
$hashtable = @{ Key1 = 'Value1'
Key2 = 2
Key3 = '3' }
Good:
$hashtable = @{
Key1 = 'Value1'
Key2 = 2
Key3 = '3'
}
Good:
$hashtable = @{
Key1 = 'Value1'
Key2 = 2
Key3 = @{
Key3Key1 = 'ExampleText'
Key3Key2 = 42
}
}
There should not be any commented-out code in checked-in files. The first letter of the comment should be captialized.
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 comment inside the brackets should be indented once more than the brackets.
The brackets should be indented the same amount as the following line of code.
Formatting help-comments for functions has a few more specific rules that can be found here.
Bad:
function Get-MyVariable
{#this is a bad comment
[CmdletBinding()]
param ()
#this is a bad comment
foreach ($example in $examples)
{
Write-Verbose -Message $example #this is a bad comment
}
}
Bad:
function Get-MyVariable
{
[CmdletBinding()]
param ()
# this is a bad comment
# On multiple lines
foreach ($example in $examples)
{
# No commented-out code!
# Write-Verbose -Message $example
}
}
Good:
function Get-MyVariable
{
# This is a good comment
[CmdletBinding()]
param ()
# This is a good comment
foreach ($example in $examples)
{
# This is a good comment
Write-Verbose -Message $example
}
}
Good:
function Get-MyVariable
{
[CmdletBinding()]
param ()
<#
This is a good comment
on multiple lines
#>
foreach ($example in $examples)
{
Write-Verbose -Message $example
}
}
For all indentation, use 4 spaces instead of tabs. There should be no tab characters in the file unless they are in a here-string.
Backticks should always be directly followed by a newline
All files must end with a newline, see StackOverflow.
Save newlines using CR+LF instead of CR. For interoperability reasons, we recommend that you follow these instructions when installing Git on Windows so that newlines saved to GitHub are simply CRs.
Code should not contain more than two consecutive newlines unless they are contained in a here-string.
Bad:
function Get-MyValue
{
Write-Verbose -Message 'Getting MyValue'
return $MyValue
}
Bad:
function Get-MyValue
{
Write-Verbose -Message 'Getting MyValue'
return $MyValue
}
function Write-Log
{
Write-Verbose -Message 'Logging...'
}
Good:
function Get-MyValue
{
Write-Verbose -Message 'Getting MyValue'
return $MyValue
}
Good:
function Get-MyValue
{
Write-Verbose -Message 'Getting MyValue'
return $MyValue
}
function Write-Log
{
Write-Verbose -Message 'Logging...'
}
Each curly brace should be preceded by a newline unless assigning to a variable.
Bad:
if ($booleanValue) {
Write-Verbose -Message "Boolean is $booleanValue"
}
Good:
if ($booleanValue)
{
Write-Verbose -Message "Boolean is $booleanValue"
}
When assigning to a variable, opening curly braces should be on the same line as the assignment operator.
Bad:
$scriptBlockVariable =
{
Write-Verbose -Message 'Executing script block'
}
Bad:
$hashtableVariable =
@{
Key1 = 'Value1'
Key2 = 'Value2'
}
Good:
$scriptBlockVariable = {
Write-Verbose -Message 'Executing script block'
}
Good:
$hashtableVariable = @{
Key1 = 'Value1'
Key2 = 'Value2'
}
Each opening curly brace should be followed by only one newline.
Bad:
function Get-MyValue
{
Write-Verbose -Message 'Getting MyValue'
return $MyValue
}
Bad:
function Get-MyValue
{ Write-Verbose -Message 'Getting MyValue'
return $MyValue
}
Good:
function Get-MyValue
{
Write-Verbose -Message 'Getting MyValue'
return $MyValue
}
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-MyValue
{
Write-Verbose -Message 'Getting MyValue'
return $MyValue
} Get-MyValue
Bad:
function Get-MyValue
{ Write-Verbose -Message 'Getting MyValue'
if ($myBoolean)
{
return $MyValue
}
else
{
return 0
}
}
Get-MyValue
Good:
function Get-MyValue
{
Write-Verbose -Message 'Getting MyValue'
if ($myBoolean)
{
return $MyValue
}
else
{
return 0
}
}
Get-MyValue
If you must declare a variable type, type declarations should be separated from the variable name by a single space.
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param ()
[Int]$number = 2
}
Good:
function Get-TargetResource
{
[CmdletBinding()]
param ()
[Int] $number = 2
}
There should be one blank space on either side of all operators.
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param ()
$number=2+4-5*9/6
}
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param ()
if ('example'-eq'example'-or'magic')
{
Write-Verbose -Message 'Example found.'
}
}
Good:
function Get-TargetResource
{
[CmdletBinding()]
param ()
$number = 2 + 4 - 5 * 9 / 6
}
Good:
function Get-TargetResource
{
[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-TargetResource
{
[CmdletBinding()]
param ()
if('example' -eq 'example' -or 'magic')
{
Write-Verbose -Message 'Example found.'
}
foreach($example in $examples)
{
Write-Verbose -Message $example
}
}
Good:
function Get-TargetResource
{
[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.
Bad:
function get-targetresource
{
# ...
}
Good:
function Get-TargetResource
{
# ...
}
All function names must follow the standard PowerShell Verb-Noun format.
Bad:
function TargetResourceGetter
{
# ...
}
Good:
function Get-TargetResource
{
# ...
}
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,
[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,
[ValidateSet('operational', 'debug', 'analytic')]
[String]
$Channel = 'operational'
)
# Implementation
}
There must be a parameter block decalred for every function. The parameter block must be at the top of the function and not declared next to the function name. Functions with no parameters should still display an empty parameter block.
Bad:
function Write-Text([Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$Text)
{
Write-Verbose -Message $Text
}
Bad:
function Write-Nothing
{
Write-Verbose -Message 'Nothing'
}
Good:
function Write-Text
{
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Text
)
Write-Verbose -Message $Text
}
Good:
function Write-Nothing
{
param ()
Write-Verbose -Message 'Nothing'
}
An empty parameter block should be displayed on its own line like this: param ()
Otherwise, the opening and closing parentheses should each be on their own line.
All text inside the parameter block should be indented once.
Bad:
function Write-Nothing
{
param
(
)
Write-Verbose -Message 'Nothing'
}
Bad:
function Write-Text
{
param([Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String] $Text )
Write-Verbose -Message $Text
}
Good:
function Write-Nothing
{
param ()
Write-Verbose -Message 'Nothing'
}
Good:
function Write-Text
{
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Text
)
Write-Verbose -Message $Text
}
All parameters must use PascalCase.
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param
(
$SOURCEPATH
)
}
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param
(
$sourcepath
)
}
Good:
function Get-TargetResource
{
[CmdletBinding()]
param
(
$SourcePath
)
}
Parameters must be separated by a single, blank line.
Bad:
function New-Event
{
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Message,
[ValidateSet('operational', 'debug', 'analytic')]
[String]
$Channel = 'operational'
)
}
Good:
function New-Event
{
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Message,
[ValidateSet('operational', 'debug', 'analytic')]
[String]
$Channel = 'operational'
)
}
The parameter type must be on its own line above the parameter name. If an attribute needs to follow the type, it should also have its own line between the parameter type and the parameter name.
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param
(
[String] $SourcePath = 'c:\'
)
}
Good:
function Get-TargetResource
{
[CmdletBinding()]
param
(
[String]
$SourcePath = 'c:\'
)
}
Good:
function Get-TargetResource
{
[CmdletBinding()]
param
(
[PSCredential]
[Credential()]
$MyCredential
)
}
Good:
function New-Event
{
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Message,
[ValidateSet('operational', 'debug', 'analytic')]
[String]
$Channel = 'operational'
)
}
Parameter attributes should each have their own line. All attributes should go above the parameter type, except those that must be between the type and the name.
Bad:
function New-Event
{
param
(
[Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]
$Message,
[ValidateSet('operational', 'debug', 'analytic')][String]
$Channel = 'operational'
)
}
Good:
function New-Event
{
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$Message,
[ValidateSet('operational', 'debug', 'analytic')]
[String]
$Channel = 'operational'
)
}
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."
}
Call cmdlets using named parameters instead of positional parameters.
Bad:
Get-ChildItem C:\Documents *.md
Good:
Get-ChildItem -Path C:\Documents -Filter *.md
When calling a function use the full command not an alias.
You can get the full command an alias is using by calling Get-Alias
.
Bad
ls -File $root -Recurse | ? { @('.gitignore', '.mof') -contains $_.Extension }
Good
Get-ChildItem -File $root -Recurse | Where-Object { @('.gitignore', '.mof') -contains $_.Extension }