These guidelines shall be interpreted according to the doctrine of lex specialis. In other words, where two guidelines apply to the same situation, the more specific guideline prevails.
constructor property - a public resource parameter or property that is a required parameter of the resource's constructor. Every constructor property is a hint but not every hint is a constructor property.
DSC algorithm - the process that successively invokes DSC resources to converge on a configuration.
hint - a public resource parameter or property that is passed to the resource's constructor.
key - a mandatory public resource parameter or property that uniquely identifies a resource instance.
property - a property of a resource instance. A property can be set and tested by passing a value to its corresponding public resource parameter. A property cannot be created or removed from its resource instance.
resource instance - an instance of a resource that can be created and removed using Set Present
and Set Absent
, respectively.
public resource class - the class with the [DscResource()]
object that is used to publish a resource.
public resource function - a function that is invoked by Set()
and Test()
of a corresponding public resource class and is also exported as a public interface to the module.
public resource parameter - a parameter of a public resource function.
public resource property - a property of a public resource class bearing the [DscProperty()]
attribute.
Reason
Invoking Set Present
may lead to invoking the constructor for resource. If the resource has constructor properties those must also be provided
otherwise construction will fail.
Enforcement
This can be enforced by checking for missing constructor properties whenever Set Present
is invoked.
Reason
This simplifies testing because the removed state provides a consistent baseline from which to test configurations.
Enforcement
Invoke the public resource function as follows:
-
Set Absent
-
Test Absent
and confirm the return value is$true
.
Reason
To be usable, a resource instance must be present. A resource instance can be removed per C.1. Accordingly, for a resource instance to be usable, it must be possible to add it.
Enforcement
Invoke the public resource function as follows:
-
Set Absent
to reset -
Set Present
to add it -
Test Present
and confirm the return value is$true
Reason
This is required to support C.1.
Enforcement
Invoke the public resource function as follows:
-
Set Absent
to reset -
Set Present
-
Set Absent
-
Test Absent
and confirm the return value is$true
Reason
A resource cannot be both present and absent.
Enforcement
Invoke the public resource function as follows:
-
Set Absent
to reset -
Set Present
to add it -
Test Absent
and confirm the return value is$false
Reason
A resource cannot be both absent and present.
Enforcement
Invoke the public resource function as follows:
-
Set Absent
to reset -
Test Present
and confirm the return value is$false
The following should probably also be tested:
-
Set Absent
to reset -
Set Present
-
Set Absent
-
Test Present
and confirm the return value is$false
Reason
If a property cannot be set after construction and a resource instance exists with a different property value, the DSC algorithm will never converge.
Reason
This is to avoid requiring multiple passes of the DSC algorithm to achieve convergence. A property that cannot be set on construction will cause the test following the set to fail. Such a failure will cause the DSC engine to halt further configuration.
Reason
A module can be available using Get-Module -ListAvailable
but fails on import.
Reason
Confusion can result during testing if PowerShell unexpectedly loads another available module (perhaps with a different version) with the same name.
Reason
The nested module must be imported to test the class inside it.
Reason
This simplifies testing because the nested module can be accessed by name alone.
Reason
This is to simplify discovery of public resource classes by automated tests. Discovery of nested modules is trivial.
Reason
Related resources usually share an amount of utility code. Publishing related resources in a single parent module facilitates sharing a single copy of such utility code.
Enforcement
Invoke Get-DscResource
for each of the related public resources and confirm that the module name is the parent module.
L.3 The Set and Test methods of the public resource class simply invoke the corresponding public function.
Reason
Complexity is easier to test in functions than classes. The least amount of complexity that can be in the Set()
and Test()
methods of a public resource class is to simply invoke their corresponding public resource function.
This is as opposed to using MOF files to publish resources.
Reason
The particulars of the class can easily be tested using PowerShell. Testing the same information in a MOF-based resource would require a parser for MOF files.
Reason
There might be subtle differences between the public resource class and the resultant object produced by PowerShell/WMF. Accessing the resultant object from Get-DscResource
enables testing public resource properties as interpreted by PowerShell/WMF.
Reason
Functions are more easily tested than classes. Exposing a public function that is also invoked by the resource facilitates isolated testing.
Reason
This is to simplify discovery of the public function from the public resource class and vice versa.
Reason
This simplifies testing because the module and its DSC resources are accessed by name alone.
Reason
Parameters are passed to class-based resources via public resource class properties with the [DscProperty()]
attribute. A resource must have at least one such property.
A public resource class has an optional Ensure
property. It is of type [Ensure]
and has default value Present
.
Reason
The name Ensure
should only be used to specify whether a resource is present or absent because that is its customary meaning in PowerShell DSC. Ensure
is of type [Ensure]
so that it can only take the values Present
and Absent
. Ensure
has default value Present
because omitting Ensure
should cause the resource to ensure presence.
Reason
Omitting optional parameters means the configuration affected by the parameter should remain unchanged. A default value for a public resource property defeats that behavior because the configuration gets set to the default value when the parameter is omitted.
This rule was removed because a resource author could reasonably opt that an omitted value should change the affected configuration to a default value. A user can still override such behavior by specifying $null
for such a parameter thereby preventing any change to the affected configuration.
Each public resource function has a mandatory Mode
parameter. The Mode
parameter is of type [Mode]
. Mode
is the first positional argument and does not have a default value.
Reason
The mode parameter is required to select between Test
and Set
. It is of type [Mode]
to restrict its values to Set
and Test
. Because it is mandatory, a default value has no use. Mode
is the first positional argument to support readability at call sites (e.g. Invoke-Resource Test
).
Each public resource function has an optional Ensure
parameter. The Ensure
parameter is of type [Ensure]
. Ensure
is the second positional argument and has default value Present
.
Reason
The name Ensure
should only be used to specify whether a resource is present or absent because that is its customary meaning in PowerShell DSC. Ensure
is of type [Ensure]
so that it can only take the values Present
and Absent
. Ensure
is the second positional argument to support readability at call sites (e.g. Invoke-Resource Test Absent
). Ensure
has default value Present
because omitting Ensure
should cause the resource to ensure presence.
No public resource parameter should have the ValueFromPipeline
attribute set.
Reason
This is to improve parameter binding predictability. With ValueFromPipeline
set it is difficult to predict which, if any, parameter a pipeline value will bind to.
Each public resource parameter should have the ValueFromPipelineByPropertyName
attribute set.
Reason
This is to support binding of bulk parameters using objects. In particular, it supports passing the values of member variables of a [DscResource()]
object as arguments to the function (e.g. $this | Invoke-Resource Set
).
Reason
This is to avert confusion that might result when bulk-binding the values of a public resource properties to public resource parameters using the pipeline (e.g. $this | Invoke-Resource
). The correct value for Mode
must be explicitly passed to the public resource function (e.g. "Test
" in Invoke-Resource Test
) on each invocation of the Set()
and Test()
methods. The existence of a Mode
property probably indicates an error. That is, a resource author is probably incorrectly expecting Mode
to be passed from a public resource property by the pipeline.
Reason
This is to help users understand what kind of object is expected for each parameter.
Reason
This is to support compliance with PR.12 when a user omits a [string]
. Per PowerShell/PowerShell#4616, passing $null
to a [string]
parameter unconditionally causes conversion to [string]::empty
. This silently converts the meaning from "don't change" to "clear value" which is incorrect. PowerShell only performs such a silent conversion from $null
for [string]
s. To avoid this problem and still use static-typing you can use [NullsafeString]
instead.
Because PR.12 does not apply to mandatory parameters, this rule also does not apply to mandatory parameters.
Reason
This is to support compliance with PR.12 when a user omits a value-type parameter. Normal value-type parameters in .Net cannot be $null
.
Exceptions
This rules does not apply to the Ensure
public resource parameter because it cannot be null.
PR.12 The meaning of null for an optional default-less public resource property or parameter is the same as omitting it.
Reason
Omission of an optional default-less parameter P means "don't change" P. Such an omitted parameter takes the value $null
while it is embodied as the value of a public resource property. This is because there is no other built-in mechanism that means unbound, unspecified, or omitted for public resource properties. Accordingly, all callees interpreting such a parameter must consider $null
to mean "don't change".
This rule does not apply to mandatory parameters because they can neither be null (by PR.14) nor omitted (because they are mandatory).
Reason
This is to support compliance with PR.11 when a user omits a value-type parameter. Value-type parameters in .Net cannot be $null
.
Exception
This rule does not apply to the Ensure
public resource property.
Reason
This is to support compliance with PR.11. Mandatory public resource parameters are not permitted to be $null
because the meaning of $null
is the same as omission per PR.11. [AllowNull()]
does not affect non-mandatory parameters. Therefore, [AllowNull()]
on public resource parameters either indicates an error or is unnecessary. Always omitting [AllowNull()]
avoids errors with no downside.
Reason
This is to support parity between the interfaces published by the public resource class and public resource function.
Reason
This is to support parity between the interfaces published by the public resource class and public resource function.
Reason
This is to ensure the same behavior whether the resource is invoked using the public resource class or function.
Reason
This is to ensure the same behavior whether the resource is invoked using the public resource class or function.
Reason
This is to ensure the same behavior whether the resource is invoked using the public resource class or function.
PR.20 Public resource parameters that correspond to constructor properties are marked with an attribute.
Reason
This is so that libraries interpreting public resource parameters are able to correctly pass required properties to a resource's constructor.
PR.21 Each public resource parameter whose corresponding public resource property bears [DscProperty(Key)]
bears [StructuredResource('Key')]
Reason
This is to ensure that libraries interpreting public resource parameters are able to correctly identify Key parameters.