PowerShell DSC Blog Series – Part 3, Testing DSC Resources

For part 3 in this series I would like to illustrate some ideas on testing PowerShell Desired State Configuration resources during the authoring process.  I will once again call out that I’m not attempting to define ‘best practices’, this is just what has worked well for me and something I can share with the community.

If you are just catching this post and wondering why it is called “Part 3”, here are links to the previous posts in this series.

Part 1, Information about DSC https://blogs.technet.com/b/privatecloud/archive/2014/04/25/desired-state-configuration-blog-series-part-1-learning-about-dsc.aspx

Part 2, Authoring DSC when cmdlets already exist

https://blogs.technet.com/b/privatecloud/archive/2014/05/02/powershell-dsc-blog-series-part-2-authoring-dsc-resources-when-cmdlets-already-exist.aspx

 

I recently asked a DSC test engineer to validate a ‘hello world’ example to help me understand what testing a resource should involve.  What I learned is I can do three simple things that prevent me from looking like a rookie.  The key to doing this without feeling like it is an extra burden is the word ‘simple’.

  1. It isn’t enough to verify a Resource by testing it using a Configuration script.  I need to test each function independently and include simple written examples, and expected outcomes.  This can be accelerated using just 2 extra lines.
  2. Use the Test-DSCResource in xResourceDesigner.  I have a script I will share to automate this for you.
  3. Provide example Configuration scripts and a walk-through of what I am describing as ‘the 3 scenarios’.

Then, and only then, are you ready to actually have someone else look at your script.

 


1.  Two Lines that make your DSC module functions 10 times easier to understand.

When you create a DSC resource, you have script modules that define “Get, Set, and Test”.  Each of these are a unique Function within the module.  ‘Module’ by the way is just another way of saying a special kind of script file.

Here is the shortest Get example I can come up with.  The point of this is to illustrate lines 5 and 6.

001002003004005006 function Get-TargetResource {param ($string) @{'name' = $string}}# Get-TargetResource "foo"# Expected output is a hashtable with the name property and a value of "foo"

 

For each function, include an example with working values.  Anyone should be able to open your function and be able to run a test manually by walking through Get, Test, and Set.  Under that example, provide a very brief statement about what should be returned.

Second to this, don’t be afraid to include Write-Verbose statements that share what the script is working with through each step.  A nice place for this type of thing is in the Test function.  Before you output a Boolean, Write-Verbose something simple for anything that failed so whoever is doing the testing can more easily understand what is happening without having to assume.

Here is a very short example.

001002003004005006007008009010011012013 function Test-TargetResource {param ($string) $Test = Get-ExampleCmdlet If ($Test -eq $string) { $true } else { Write-Verbose "The test expected `"$string`" but returned a value of: $Test" $false }}# Test-TargetResource "foo"# Expected output is a boolean 'True'

 


2. Save time by using the Test functionality in Resource Designer

I have gotten a lot of value out of the Resource Designer tool published by the PowerShell DSC team.  It is a quick way to make sure what I created follows best practices.  You can download the tool from the TechNet gallery.

xDscResourceDesigner Module –PowerShell Desired State Configuration Resource Kit
https://gallery.technet.microsoft.com/scriptcenter/xDscResourceDesigne-Module-22eddb29

After you download this tool and copy it to your Modules folder, the commands for testing your resources are:

  • Test-xDscResource
  • Test-xDscSchema

Some examples of best practices this will help you check are that the data types are the same between your schema file and your scripts, that your parameters are the same for Set and Test, that mandatory parameters are the same in all three functions, and that any parameters marked as Mandatory in the scripts are set as Required in the schema file.

I created this quick snippet that makes it even easier to test all modules across a resource by looping across each.

001002003004005006007008009010011012013014015016017018019020021022023 $TestModule = 'cExampleResourceName'$DSC = Get-DscResourcewrite-host `nwrite-host " Testing each resource in module: " -NoNewlinewrite-host "$TestModule" -ForegroundColor blue -BackgroundColor darkyellowwrite-host `nforeach ($Resource in ($DSC | ? {$_.Module.Name -eq $TestModule})) {write-host "Running Tests against $($Resource.Name) resource" -ForegroundColor Yellowtry { $Result = Test-xDscResource -Name $Resource.Name switch ($Result) { $True {write-host "All tests passed for $($Resource.Name)." -ForegroundColor Green} $False {write-host "One or more tests failed for $($Resource.Name)." -ForegroundColor Red} } write-host `n }catch { Write-Warning "The test for $($Resource.Name) failed due to an error" write-host `n }}

 

 


3. Provide examples of ‘the 3 scenarios’

Finally, you are going to want to create example Configuration scripts and a good ReadMe file.  Remember that even though at the time you are authoring the scripts it is obvious to you how they should work, when you hand them off to someone else they probably don’t have that same level of detail.  I generally like to include a summary, requirements, a ‘how-to’ section, and then specifically explain any advanced concepts if any exist.

If you choose to create a ReadMe and you are not sure what you need to demonstrate, I have combined some thoughts from various community discussions in to a concept I like to refer to as ‘the 3 scenarios’.

  • Create – applies a configuration
  • Remove – removes whatever was applied during Create
  • Configure – if the thing that was created has changed, put it back

What this amounts to is one-line examples.  I would include at least two Configuration scripts.  One that ensures the configuration is Present (create) and one that ensures it is Absent (remove).  I would include a short script that changes something that should be managed by DSC such as a registry key or the outcome of a script, so whoever is doing the testing does not have to guess.  Finally, I would include instructions on running the required steps to restore the intended configuration using *-DSCConfiguration cmdlets.

 


In summary, the point of this exercise is for you to test your own work with the intention that when you feel like you have met a quality bar, you will ask someone else to test it for you.  It is easier to ask someone for a “sanity check” when all they need to do is copy and paste 1-liners from a ReadMe file than putting them in the position of guessing, where they will likely end up frustrated.  Keeping this quick and painless will also mean they might be willing to help you again in the future, and might be willing to provide you with the same level of detail if they need you to test their work.

Thanks and stay tuned to Building Clouds!