Although adopting the best practices is optional, doing so will help improve the quality of the DSC resource module.
Note: Modules that aim to meet the High Quality Resource Module standards must also implement the best practices wherever possible.
Using hard coded computer names exposes sensitive information on your machine. Use a parameter or environment variable instead if a computer name is necessary. This comes from this PS Script Analyzer rule.
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.
This rule has a few exceptions:
$global:DSCMachineStatus
is still recommended to restart a
machine from a DSC resource.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
)
}
This is a script not a console. Code should be easy to follow. There should be no more than 1 pipe in a line. This rule is specific to the DSC Resource Kit - other PowerShell best practices may say differently, but this is our preferred format for readability.
Bad:
Get-Objects | Where-Object { $_.Propery -ieq 'Valid' } | Set-ObjectValue `
-Value 'Invalid' | Foreach-Object { Write-Output $_ }
Good:
$validPropertyObjects = Get-Objects | Where-Object { $_.Property -ieq 'Valid' }
foreach ($validPropertyObject in $validPropertyObjects)
{
$propertySetResult = Set-ObjectValue $validPropertyObject -Value 'Invalid'
Write-Output $propertySetResult
}
If it is clear what type a variable is then it is not necessary to explicitly declare its type. Extra type declarations can clutter the code.
Bad:
[String] $myString = 'My String'
Bad:
[System.Boolean] $myBoolean = $true
Good:
$myString = 'My String'
Good:
$myBoolean = $true