Defining a DSC configuration data file

In the previous sections, we covered using DSC configuration script files with DSC configuration data, but we have not covered exactly how you specify configuration data or how it is stored separately from the configuration scripts. In this section, we will cover this and the rules applying to what configuration data can be specified, as well as some best practices for using it.

When we refer to DSC configuration data, we are referring to any environmental data supplied to the DSC configuration function. This may be slightly confusing, as we mentioned a DSC special variable called $ConfigurationData earlier in this chapter. Try to remember when we refer to the DSC configuration data term that, we are referring to the entirety of the data supplied to the configuration function, not just the data available through the special variable called $ConfigurationData.

DSC configuration data can be supplied either through a hashtable or as a PowerShell manifest file (a file with a .psd1 extension) passed to the configuration function parameter. For the majority of the time, you will be using data files instead of the hashtable approach, as these increase flexibility by allowing you to switch out data files when compiling to MOF.

Some of the examples you might see online when first learning about DSC show passing the data directly to the DSC Configuration block and defining that data in the same file. Although probably done to simplify the example, this defeats the point of CM that we covered in the first chapter, as well as providing bad examples for new users. In this book, we will cover in detail how to pass configuration data to DSC Configuration blocks from external files, but you should keep in mind that you can also do this from inside your script using an ordinary hashtable.

Authoring DSC configuration data files

As with DSC configuration scripts, you can use any text editor to author them. Since there is little else needed other than some syntax highlighting, you can choose anything you desire. By convention, we use the psd1 extension to signify that this is a data manifest file. You could technically name it anything you want as you are responsible for loading the file, but in practice, this is not good form. It is best to stick with certain expected conventions, as doing so aids in discovery and maintainability later on.

Configuration data syntax

The DSC ConfigurationData hashtable must have an AllNodes key whose value is an array. This is a hard requirement; the key must be spelled correctly as DSC looks for that specific key. The error message DSC outputs when this key is incorrect is hard to figure out at first, so be sure to be correct in this to save some headaches later on. A very contrived example follows:

 [PS]> $ConfigData = @{
>>>   AllNodes = @(
>>>     @{
>>>       Node = "foo"
>>>     }
>>>   )
>>> }
[PS]>
[PS]> configuration InstallExampleSoftware
>>> {
>>>   Node "localhost"
>>>   {
>>>     WindowsFeature DotNet
>>>     {
>>>       Ensure = 'Present'
>>>       Name   = 'NET-Framework-45-Core'
>>>     }
>>>   }
>>> }
[PS]>
[PS]> InstallExampleSoftware -ConfigurationData $ConfigData
ValidateUpdate-ConfigurationData : all elements of AllNodes need to be hashtable and has a property 'NodeName'.
At
C:Windowssystem32WindowsPowerShellv1.0ModulesPSDesiredStateConfigurationPSDesiredStateConfiguration.psm1:1816
char:30
+ ...  $dataValidated = ValidateUpdate-ConfigurationData $ConfigurationData
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Write-Error], InvalidOperationException
    + FullyQualifiedErrorId : ConfiguratonDataAllNodesNeedHashtable,ValidateUpdate-ConfigurationData
[PS]>

The AllNodes array will contain one or more hashtables that are required to have one key called NodeName. Again, including this key and spelling it correctly is important for the same reasons as discussed previously. A special hashtable may be included that uses the * as the value for the NodeName instead of an actual node name. This special hashtable acts as default values for all the other hashtable nodes. This allows you to specify sensible defaults or values that apply to all target nodes, while still allowing the individual target node hashtables to override the values:

@{
  AllNodes = @(
    @{
      NodeName = "server1"
      Roles    = @('Foobar')
      ExampleSoftware = @{
        Name       = "ExampleSoftware"
        ProductId  = "{b652663b-867c-4d93-bc14-8ecb0b61cfb0}"
        SourcePath = "c:packages	hesoftware.msi"
        ConfigFile = "c:foo.txt"
      }
    },
    @{
      NodeName = "server2"
    }
  ); 
  NonNodeData = @{
    ConfigFileContents = (Get-Content "Config.xml")
  }
}

There are two ways you can assign configuration data to a DSC Configuration block: by variable or by file. Variable syntax usage is fairly straightforward and easy to specify but is hard to maintain in the long term. The data is separate from the DSC Configuration block, but is still present in the file, so we have not gotten much separation and insulation from change. Data file syntax is slightly more complex, but it is more flexible and easier to maintain in the long run. It fully separates the data from the configuration file.

The variable syntax

You can assign the hashtable to a variable and pass the variable to the configuration parameter like so:

$TheData = @{
  AllNodes = @(
    @{
      NodeName = "server1"
      Roles    = @('Foobar')
      ExampleSoftware = @{
        Name       = "ExampleSoftware"
        ProductId  = "{b652663b-867c-4d93-bc14-8ecb0b61cfb0}"
        SourcePath = "c:packages	hesoftware.msi"
        ConfigFile = "c:foo.txt"
      }
    },
    @{
      NodeName = "server2"
    }
  ); 
  NonNodeData = @{
    ConfigFileContents = (Get-Content "Config.xml")
  }
}

InstallExampleSoftware -ConfigurationData $TheData

You can also assign the hashtable directly to the configuration function:

InstallExampleSoftware -ConfigurationData @{
  AllNodes = @(
    @{
      NodeName = "server1"
      Roles    = @('Foobar')
      ExampleSoftware = @{
        Name       = "ExampleSoftware"
        ProductId  = "{b652663b-867c-4d93-bc14-8ecb0b61cfb0}"
        SourcePath = "c:packages	hesoftware.msi"
        ConfigFile = "c:foo.txt"
      }
    },
    @{
      NodeName = "server2"
    }
  ); 
  NonNodeData = @{
    ConfigFileContents = (Get-Content "Config.xml")
  }
}

The data file syntax

A DSC Configuration data file is a PowerShell manifest file (a file with a .psd1 extension) that contains a single hashtable. This hashtable follows the same rules as the hashtable above, with the exception of not being able to specify a variable name inside the file.

To create a data file, create a new file with a .psd1 extension and start adding the hashtable like the ones in the following example. Note the catchall wildcard NodeName in the first hashtable, whose values apply to all other hashtables as we discussed in the DSC special variables section earlier. Also note that the server2 hashtable overrides the default ExampleSoftware entry and specifies a new path for the MSI:

# beginning of data file
@{
  AllNodes = @(
    @{
      NodeName = "server1"
      Roles    = @('Foobar')
      ExampleSoftware = @{
        Name       = "ExampleSoftware"
        ProductId  = "{b652663b-867c-4d93-bc14-8ecb0b61cfb0}"
        SourcePath = "c:packages	hesoftware.msi"
        ConfigFile = "c:foo.txt"
      }
    },
    @{
      NodeName = "server2"
      Roles    = @('Foobar')
      ExampleSoftware = @{
        Name       = "ExampleSoftware"
        ProductId  = "{b652663b-867c-4d93-bc14-8ecb0b61cfb0}"
        SourcePath = "e:packages	hesoftware.msi"
        ConfigFile = "e:foo.txt"
      }
    },
    @{
      NodeName = "server3"
      Roles    = @('Wakka')
    }
  ); 
  NonNodeData = @{
    ConfigFileContents = (Get-Content "Config.xml")
  }}
# ending of data file

We can now use this data section with the DSC configuration script we defined in The script file example and it will work. We do this by saving the preceding hashtable to a text file and passing that file to the configuration function we defined:

InstallExampleSoftware -ConfigurationData c:exampledatafile.psd1

By specifying the data inside a configuration data file, you gain flexibly of separating data from logic. We covered this in Chapter 2, DSC Architecture, and here we really see its power. Imagine an environment of a thousand servers divided into test, staging, and production. You could have one configuration data file per environment- test.psd1, staging.psd1, and production.psd1- and have one DSC configuration script called install.psd1. Each of the .psd1 files has a list of target nodes in it, along with all the environment-specific configuration information. When compiling to MOF, all environment-specific information is coded and handled.

Allowable DSC configuration content

DSC configuration data files follow the same restricted language set of rules that PowerShell data sections have. A PowerShell data section is a block of text that contains only data and a limited subset of the general PowerShell language.

The allowed code is limited to the following:

  • All PowerShell operators, with the exception of –match
  • If, Else, and ElseIf statements
  • The following automatic variables:
    • $PSCulture
    • $PSUICulture
    • $True
    • $False
    • $Null
  • Comments
  • Pipelines
  • Statements separated by semicolons
  • Any Cmdlets that you permit explicitly in a data section by using the SupportedCommand parameter

This effectively means that there is little code you can put inside a DSC configuration data file by default. While this sounds like a bad limitation, in practice it's a good thing as it prevents you from trying to put too much logic in what should be a data-only file. Remember, all the times we covered why you should be putting the decision-making logic inside DSC Resources apply here.

There is one case where you might want some small bits of code to be inside DSC configuration data files. Since we are dealing with environmental data, you may have different application configuration files or, artifacts, or an installation file path to include in your data files, depending on which environment or aspects of a target node you are operating on. Choosing which sets of data to include in your file may be something you need to do from time to time. For example, a production web server may have a different web.config file than the development web server, possibly in different locations as well. Keeping in mind the list we just covered, we will notice that we can't include Cmdlet names in the file. If this is the case, how can we use conditional logic?

The trick is changing how we load the DSC configuration data file. We already covered loading external data files by passing their paths to the Configuration function parameter ConfigurationData, and we can build on that to pass any configuration data we want.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset