In order to provide clean and consistent code, please follow the coding conventions listed below when contributing to this repository and all DSC Resource Kit repositories.
For general PowerShell best practices, please refer to PowerShell Best Practices document.
- For all indentation, use 4 spaces instead of tab stops
- Make sure all files are encoding using UTF-8.
- Windows handles newlines using CR+LF instead of just 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.
- When writing Markdown, 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. - Files must end with a newline, see StackOverflow.
Bad:
Function Get-MyValue
{
Write-Verbose 'Getting MyValue'
return $MyValue
}
The above code breaks this rule by having two new lines between the Write-Verbose and the return statement.
Good:
Function Get-MyValue
{
Write-Verbose 'Getting MyValue'
return $MyValue
}
Bad:
Function Get-MyValue
{
Write-Verbose 'Getting MyValue'
return $MyValue
}
The code above breaks this rule by leaving a blank line after the opening curly brackets.
Good:
Function Get-MyValue
{
Write-Verbose 'Getting MyValue'
return $MyValue
}
Bad:
if ($connected) {
Write-Verbose 'Connected to server'
}
Good:
if ($connected)
{
Write-Verbose 'Connected to server'
}
Bad:
$convertToCimUnjoinCredential = New-CimInstance -ClassName MSFT_Credential -Property @{Username=[string]$UnjoinCredential.UserName; Password=[string]$null} -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly
Good:
$convertToCimUnjoinCredential = New-CimInstance -ClassName MSFT_Credential `
-Property @{Username=[string]$UnjoinCredential.UserName; Password=[string]$null} `
-Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly
Bad:
$rdsHost = Get-RdsHost
Good:
$remoteDesktopSessionHost = Get-RemoteDesktopSessionHost
Bad:
function getTargetResource
{
# ...
}
Good:
function Get-TargetResource
{
# ...
}
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param
(
$SOURCEPATH
)
}
Good:
function Get-TargetResource
{
[CmdletBinding()]
param
(
$SourcePath
)
}
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param
(
[String]
$SourcePath = 'c:\'
}
Good:
function Get-TargetResource
{
[CmdletBinding()]
param
(
[String] $SourcePath = 'c:\'
)
}
Bad:
function Get-TargetResource
{
[CmdletBinding()]
param
(
[String]$SourcePath = 'c:\'
)
}
Good:
function Get-TargetResource
{
[CmdletBinding()]
param
(
[String] $SourcePath = 'c:\'
)
}
Bad:
function New-EtwEvent
{
param
(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Message,
[ValidateSet("operational", "debug", "analytic")]
[String] $Channel = "operational"
)
}
Good:
function New-EtwEvent
{
param
(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Message,
[ValidateSet("operational", "debug", "analytic")]
[String] $Channel = "operational"
)
}
Bad:
function New-EtwEvent
{
param
(
[Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][String] $Message,
[ValidateSet("operational", "debug", "analytic")][String] $Channel = "operational"
)
}
Good:
function New-EtwEvent
{
param
(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Message,
[ValidateSet("operational", "debug", "analytic")]
[String] $Channel = "operational"
)
}
Names of variables should use camelCase
Bad:
function New-Log
{
$Message = "New log message" # should start with lower case
Write-Host $Message
}
Good:
function New-Log
{
$message = "New log message"
Write-Host $message
}
When commenting functions, use comment-based help syntax
Bad:
# Writes event
function New-EtwEvent
{
param
(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Message,
[ValidateSet("operational", "debug", "analytic")]
[String] $Channel = "operational"
)
# Implementation
}
Good:
<#
.SYNOPSIS Writes event to ETW
.PARAM
Message Message to write to ETW
.PARAM
Channel ETW channel where message should be stored
.EXAMPLE
New-EtwEvent -Message "Attempting to connect to server" -Channel "debug"
#>
function New-EtwEvent
{
param
(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Message,
[ValidateSet("operational", "debug", "analytic")]
[String] $Channel = "operational"
)
# Implementation
}
Bad:
Get-ChildItem c:\documents *.md
The above code breaks this rule using by calling Get-ChildItem
passing positional parameters instead of named parameters.
Good:
Get-ChildItem -Path c:\documents -Filter *.md
Bad:
$Parameters = @(
@{ Name = 'Name'; Source = $FirewallRule.Name;
Type = 'String' },
@{ Name = 'DisplayName'; Source = $FirewallRule.DisplayName; Type = 'String' },
@{
Name = 'Group'
Source = $FirewallRule.Group
Type = 'String'
},
@{ Name = 'DisplayGroup'; Source = $FirewallRule.DisplayGroup; Type = '' }
)
The above array of hash table objects is not consistent. Care must be taken that each hash table or object does not exceed the 100 character maximum line width rule.
Good:
$Parameters = @(
@{ Name = 'Name'; Source = $FirewallRule.Name; Type = 'String' },
@{ Name = 'DisplayName'; Source = $FirewallRule.DisplayName; Type = 'String' },
@{ Name = 'Group'; Source = $FirewallRule.Group; Type = 'String' },
@{ Name = 'DisplayGroup'; Source = $FirewallRule.DisplayGroup; Type = '' }
)
Good:
$Parameters = @(
@{
Name = 'Name'
Source = $FirewallRule.Name
Type = 'String'
},
@{
Name = 'DisplayName'
Source = $FirewallRule.DisplayName
Type = 'String'
},
@{
Name = 'Group'
Source = $FirewallRule.Group
Type = 'String'
},
@{
Name = 'DisplayGroup'
Source = $FirewallRule.DisplayGroup
Type = ''
}
)
Bad
ls -File -Recurse $root | ? { @('.gitignore', '.mof') -contains $_.Extension }
When writing functions use the full command not aliases
Good
Get-ChildItem -File -Recurse $root | Where-Object { @('.gitignore', '.mof') -contains $_.Extension }