Skip to content

Latest commit

 

History

History
440 lines (370 loc) · 9.65 KB

StyleGuidelines.md

File metadata and controls

440 lines (370 loc) · 9.65 KB

DSC Resource Style Guidelines

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.

General Rules

  1. For all indentation, use 4 spaces instead of tab stops
  2. Make sure all files are encoding using UTF-8.
  3. 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.
  4. 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.
  5. Files must end with a newline, see StackOverflow.

PowerShell Coding Style Guidelines

Code should not contain multiple blank lines in a row

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
}

Opening curly brackets should not be followed by a blank line

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
}

Braces should always be on a following line

Bad:

if ($connected) {
    Write-Verbose 'Connected to server'
}

Good:

if ($connected)
{
    Write-Verbose 'Connected to server'
}

Each line should have less than 100 characters

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

Use verbose, easy to understand names

Bad:

$rdsHost = Get-RdsHost

Good:

$remoteDesktopSessionHost = Get-RemoteDesktopSessionHost

Function names should use PascalCase and follow Noun-Verb convention if possible

Bad:

function getTargetResource
{
    # ...
}

Good:

function Get-TargetResource
{
    # ...
}

Parameter names should use PascalCase

Bad:

function Get-TargetResource
{
    [CmdletBinding()]
    param
    (
        $SOURCEPATH
    )
}

Good:

function Get-TargetResource
{
    [CmdletBinding()]
    param
    (
        $SourcePath
    )
}

Parameter type should be on the same line as parameter name

Bad:

function Get-TargetResource
{
    [CmdletBinding()]
    param
    (
        [String]
        $SourcePath = 'c:\'
}

Good:

function Get-TargetResource
{
    [CmdletBinding()]
    param
    (
        [String] $SourcePath = 'c:\'
    )
}

Parameter type should be separated from name by a space

Bad:

function Get-TargetResource
{
    [CmdletBinding()]
    param
    (
        [String]$SourcePath = 'c:\'
    )
}

Good:

function Get-TargetResource
{
    [CmdletBinding()]
    param
    (
        [String] $SourcePath = 'c:\'
    )
}

Parameter names should be separated by a single line

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"
    )
}

Parameter attributes should be on separate lines

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"
    )
}

Variable names should use camelCase

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
}

Support comment-based help

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
}

Call cmdlets using all named parameters instead of positional parameters

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

Hash table, Array and Object Structure should be consistent

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   = ''
    }
)

Aliases should not be used

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 }