Modularizing DSC configs

Hi fellow Powershell-users!

First thank you all for a great resourceful website!

I work in the hosting business and we would like to implement DSC to our customer’s servers.
At first eyesight, we are properly not a good candidate for DSC because all the servers we administer could potential be unique and change upon request from the customers.
Yet we would like to try implementing DSC in a test environment.
The only way we can think doing this, is by making a DSC Config file for every server that we administer.
We are thinking of building our own tool to administer the many DSC Config files for easier administration and overview.
However, I watched a video with Don Jones where he said something about modularizing the DSC Config files. He did not mention how to do it and I have been searching for a way to do it.

Essentially, we would like to use DSC in a way like adding servers in multiple Device Collections in SCCM.
We see two options for that:

  1. DSC Config file for every server, where the config files will be 95% unique
  2. Being able to modularize the config files. Still having a config file for every server, but the config file for the single server only contains unique features for that server and common features is stored in shared config files.

Hope you understand what I mean :slight_smile:

Any thoughts on how we should go on with this?

Best regards from Denmark
Stig Sörnsen

While this is something I am still trying to wrap my brain around, the DSC Team did a nice blog about this very subject a while back that you might want to check out.

http://blogs.msdn.com/b/powershell/archive/2014/02/25/reusing-existing-configuration-scripts-in-powershell-desired-state-configuration.aspx

“That is why we made configurations composable and reusable. Yes, one configuration can call another. How? That is what we are going to cover in this post. The way to make a configuration reusable is by making it what we call a composite resource. Let me walk you through an example to do just that.”

This article is most applicable to what you’re asking: Separating “What” from “Where” in PowerShell DSC

You want to set up a ConfigurationData table which describes which nodes get which features, and some number of Configuration scripts (ideally, just one) which contains the logic about what to do with nodes based on the config data. There are examples of that in the blog article, and here’s another quick, small-scale view of what that might look like.

# In practice, this hashtable is likely to be stored in a separate file, or even generated on the fly
# by reading from a configuration management database of some sort.

$configData = @{
    AllNodes = @(
        @{
            NodeName = 'Server1'
            Role = @(
                'Web'
                'Database'
            )
        }

        @{
            NodeName = 'Server2'
            Role = @(
                'FileServer'
            )

            FileServerType = 'StandardFileServer'
        }
    )

    FileServerTypes = @{
        'StandardFileServer' = @{
            Shares = @(
                @{
                    Path = 'S:\SomeFolder'
                    ShareName = 'Public'
                    # Permissions, etc
                }
            )
        }
    }
}

configuration CompanyMasterConfig
{
    # In your configuration, you get automatic access to the variables
    # $ConfigurationData and $AllNodes (where $AllNodes is a shortcut
    # for $ConfigurationData['AllNodes'] )

    Import-DscResource -Module xSmbShare

    node $AllNodes.NodeName
    {
        switch ($Node.Role)
        {
            'FileServer'
            {
                $fsType = $ConfigurationData['FileServerTypes'][$Node.FileServerType]

                for ($i = 0; $i -lt $fsType.Shares.Count; $i++)
                {
                    xSmbShare "Share_$i"
                    {
                        Name = $fsType.Shares[$i].ShareName
                        Path = $fsType.Shares[$i].Path

                        # etc
                    }
                }
            }

            'Web'
            {
                # Web server resources here.  Your configuration data probably has more information about what websites to set up, etc.
            }

            'Database'
            {
                # Database resources here
            }
        }
    }
}

# When compiling your MOF files, you pass the configuration data in as a parameter:

CompanyMasterConfig -ConfigurationData $configData

How you set up the configuration data and the configuration script is very flexible, so long as every resource that gets put into the MOF file ultimately has a unique name and all of its key properties specified. In this example, I used a “for” loop in order to inject an index value into every xSmbShare resource name. If you still might have some conflicts, you could even go so far as to generate a GUID for each resource name; it’s up to you. The only required parts of the configuration data hashtable are the AllNodes array, where each element of that array is a hashtable containing at least a NodeName key. Everything else there (Roles and FileServerType under AllNodes, and FileServerTypes up at the config data root) I just made up for the example. You can use whatever works for you; just stay away from naming any config data keys starting with “PS”, as Microsoft has reserved those for their own future use.

For my testing, I’ve recreated Steve Murawski’s structure for breaking apart configurations. This is the method he covered in his Summit session “Building Scalable Configurations with DSC.” https://powershell.org/2014/05/22/building-scalable-configurations-with-dsc/

Using his directory structure for his configurations and configuration data, it works with all his tooling scripts located at GitHub - PowerShellOrg/DSC: DSC Tools and Documentation

I’ve attached a screenshot of my directory structure. With everything in place, the single “Invoke-DscBuild” command generates all my mof files, checksums, packages up all my resources, etc. Then I just copy it to my pull server.

Invoke-DscBuild -WorkingDirectory C:\Temp `
                -DestinationDirectory C:\DSC_Output `
                -SourceModuleRoot C:\CVS\DSC\DSC_Tooling `
                -ExcludedModules Nothing `
                -ConfigurationData (Get-ConfigurationData -Path C:\CVS\DSC\DSC_Configuration -Force) `
                -ConfigurationName DCMA `
                -ConfigurationModuleName DCMAConfigurations `
                -Verbose -SkipResourcePackaging -SkipResourceCheck

Thank all of you for all of this information, I really need to get back in to this arena so I can put away the fire hoses. There is a lot of information in the above posts that all people working in DSC should go through. I need to go back through Steve’s talks to try and get a better handle of his methods to see if there is more I can apply where I am at.

With everything the others have listed above Stig, I believe you should be able to accomplish your task, and prove that DSC can handle both environments of many unique servers and farms of the same server. Part of it all comes down to having the MOF files and being able to recreate that server, and have it’s changes go through that instead of just logging in and making changes on servers.

Thank you all very much for your help. We will be looking into it and come back to update this post with our experience.

Best regards
Stig

Is it possible to do this inside of ARM templates? As far as I can tell, with an ARM template using the DSC resource, it will only run on localhost.