Leveraging Configuration Data for both DSC and Pester Tests

Leveraging Configuration Data for both DSC and Pester Tests

Posted on March 21, 2018 0 Comments

When writing code, it's important to make it modular by decoupling the code as much as possible. Check out how to accomplish this with Pester tests.


A great practice to get into when writing code is making code modular. What does this mean? Creating modular code indicates decoupling code as much as possible. It means to create small functions that call other small functions instead of creating one large script. This decoupling practice creates a codebase that's more easily modified, easier to understand and is more testable.

When it comes to Desired State Configuration (DSC), this decoupling best practice remains the same. In DSC, we have two different "types" of code; configuration data and code to apply that configuration. Although it is possible to create one large DSC configuration script combining both of them, it's not recommended. Decoupling the configuration data from the actual configuration allows you to add, remove and modify existing items inside of the configuration data without ever actually changing a line of code.

A simple DSC configuration script using a separate configuration data PSD1 file is similar to  what is shown below. This file is structured in a way that DSC understands and can read various attributes of it. Notice, inside of the NonNodeData section we have a WindowsFeature key. This could potentially store one key (as we have here) or more if need be. These will be the Windows features that are added to any targeted nodes.


Configuration Data File


    AllNodes = @(
            NodeName = '*'
            PsDscAllowDomainUser = $true
            PsDscAllowPlainTextPassword = $true
            NodeName = 'DC'
    NonNodeData = @{
        WindowsFeatures = 'XPS-Viewer'

Here's an example DSC configuration script we'll be using to leverage the configuration data below. This scripted is configured to use external configuration data as indicated by using the $AllNodes.NodeName reference, rather than a static hostname. By making this into a variable, we are controlling what hosts get targeted via configuration data.


configuration AddWindowsFeatures
    Import-DscResource -ModuleName PSDesiredStateConfiguration

    Node $ConfigurationData.AllNodes.NodeName
        ($ConfigurationData.NonNodeData.WindowsFeatures).foreach( {
            WindowsFeature $_
                Ensure = 'Present'
                Name = $_

We can now invoke this DSC configuration against a node by creating the MOF file and invoking the DSC configuration.st

PS> . C:\NewWebServer.ps1
PS> AddWindowsFeatures -ConfigurationData C:\ConfigurationData.psd1
PS> Start-DscConfiguration -Wait -Force -Path .\AddWindowsFeatures -Verbose -ComputerName DC

Listen: Defrag This- Episode 5- What's Up With PowerShell and Pester?

This will then enable the XPS-Viewer Windows feature on the DC node, but how do you know for sure? I'd like to create some Pester tests for this to run after the DSC configuration. To create a Pester test, I'd have to duplicate my efforts and maintain another list of computers to run against if I wasn't using configuration data. To test the Windows feature we just enabled, a Pester test might look something like this:

describe 'XPS-Viewer Windows feature install' {

    it 'should enable the XPS-Viewer Windows feature' {
        $result = Get-WindowsFeature -Name 'XPS-Viewer' -ComputerName DC
        $result.Installed | should be $true


This works, but we've got two references to the DC computer name. We need have a central location for all the computer names so that when we update our DSC scripts, our Pester tests will follow right along. Luckily, we're using configuration data and in that external file are all of the names of the node the DSC configuration ran against. Our Pester test can now be updated to query the same source of nodes that DSC does.

#requires -Version 5

$configData = Import-PowerShellDataFile -Path C:\ConfigurationData.psd1
$nodes = ($configData.AllNodes.NodeName).where({$_ -ne '*'})

describe 'XPS-Viewer Windows feature install' {

    foreach ($node in $nodes) {
        it "should enable the XPS-Viewer Windows feature on the [$node] node" {
            $result = Get-WindowsFeature -Name 'XPS-Viewer' -ComputerName $node
            $result.Installed | should be $true


Describing XPS-Viewer Windows feature install
  [+] should enable the XPS-Viewer Windows feature on the [DC] node 2.1s

This method now allows us to add as many computers as necessary without updating the Pester tests!

Adam Bertram

Adam Bertram is a 20-year veteran of IT. He’s currently an automation engineer, blogger, independent consultant, freelance writer, author, and trainer. Adam focuses on DevOps, system management, and automation technologies as well as various cloud platforms. He is a Microsoft Cloud and Datacenter Management MVP and efficiency nerd that enjoys teaching others a better way to leverage automation.


Comments are disabled in preview mode.

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

Loading animation