Windows Desired State Configuration - A Primer

2015-09-27T17:30:00Z

I've recently completed my first DSC deployment, as part of an upgrade to 12 IIS Servers across two data centres. Whilst I was testing DSC in my lab, I wrote a primer for my colleages. Here is that primer, with some edits. It's a rough guide but it features links to a number of useful resources.

This article concentrates on using DSC in a push configuration. That means that the configuration is applied when a system administrator manually starts DSC from their own workstation. In the coming weeks I'll be implementing a pull configuration for a development environments. This relies on a pull server from which the DSC clients are configured to fetch and apply DSC configuration.

What is DSC?

Desired State Configuration is a feature that first shipped with Windows Management Framework 4, which is in-turn closely coupled to Powershell 4.0. DSC provides an idempotent mechanism for deploying configuration changes to a target host or a group of target hosts.

Which version of Windows Work with DSC

What do you need for DSC Administration?

Prerequisites

A pc for pushing your DSC configuration which must be running any version for Windows post Windows 7/Server 2008 r2 At least one host which you can provision with DSC.

Prepare your Environment

Getting Started

The Powershell ISE can be used to author scripts and compile them into MOFs (Managed Object Files). Be aware that the MOFs will be generated in the ISE's current folder, so before starting work use the console pane to change directory (e.g. Set-Location E:\DSC)

Writing a simple DSC Script is quite a trivial business. For example, the following PowerShell script will create a DSC MOF to provision an IIS Server with the base IIS role:

Configuration IisWebServerSample1
{
    Import-DscResource –ModuleName ’PSDesiredStateConfiguration’

    Node "MyWebServer"
    {
        WindowsFeature IIS
    {
        Ensure="Present"
        Name="Web-Server"
    }
    }
}

Set-Location $env:UserProfile\Documents\ManagedObjectFiles
IisWebServerSample1

The DSC Script defines what to all intents and purposes, is a PowerShell function. The penultimate statement in the script sets our location so that executing the "function" (final step) produces a MOF in '''C:\Users\<UserName>\Dcouments\ManagedObjectFiles\MyWebServer'''.

We can now apply our compiled MOF to a target host called "MyWebServer" with the following command:

Start-DscConfiguration -Path .\IisWebServerSample1 -Wait -Verbose

You can be a bit more flexible around applying DSC configuration to different hosts. Use a parameter for your target host (node) name and then leave compiling the MOF until it's actually used, as per the following example:

Configuration IisWebServerSample2
{
    # Parameters are optional
    param($TargetNodeName)

    Import-DscResource –ModuleName ’PSDesiredStateConfiguration’

    Node $TargetNodeName
    {
        WindowsFeature IIS
    {
        Ensure="Present"
        Name="Web-Server"
    }
    }
}

To apply this configuration to Server001, use the following statements:

Set-Location -Path $env:UserProfile\Documents\ManagedObjectFiles
. $env:UserProfile\Documents\ManagedObjectFiles\DscScripts\IisWebServerSample2.ps1 -TargetNodeName Server001
Start-DscConfiguration -Path $env:UserProfile\Documents\ManagedObjectFiles\IisWebServerSample2 -Wait

Resources

DSC is all about resources. In the examples above, the resource "WindowsFeature" is used to install IIS. In short, resources enable you to "do stuff" using DSC. With WMF 4.0, Microsoft started releasing resources in waves, the latest being Wave 10. With the advent of WMF 5.0, Microsoft has introduced a NuGet Style repository type system.

You can read more about resources here.

Resource Kits and Repositories

Installing and using a Module

DSC resources are incorporated into modules. These very much resemble traditional PowerShell modules - it's only their content and use that differs slightly.

If using WMF 5.0 (not on Windows 7), installing a new module is as simple as: Install-Module -Name xSmbShare

If using WMF 4.0 you may need to find the module on GitHub, download it, and extract the contents to C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSCResources. Once it is installed, it should be immediately available to use in DSC scripts. You can check by running Get-DscResource and searching for the resource/module name, e.g.

> Get-DscResource

ImplementedAs   Name                      ModuleName                     Version    Properties                                        
-------------   ----                      ----------                     -------    ----------                                        
Binary          File                                                                {DestinationPath, Attributes, Checksum, Content...
PowerShell      Archive                   PSDesiredStateConfiguration    1.1        {Destination, Path, Checksum, Credential...}      
PowerShell      Environment               PSDesiredStateConfiguration    1.1        {Name, DependsOn, Ensure, Path...}                
PowerShell      Group                     PSDesiredStateConfiguration    1.1        {GroupName, Credential, DependsOn, Description...}
Binary          Log                       PSDesiredStateConfiguration    1.1        {Message, DependsOn, PsDscRunAsCredential}        
PowerShell      Package                   PSDesiredStateConfiguration    1.1        {Name, Path, ProductId, Arguments...}             
PowerShell      Registry                  PSDesiredStateConfiguration    1.1        {Key, ValueName, DependsOn, Ensure...}            
PowerShell      Script                    PSDesiredStateConfiguration    1.1        {GetScript, SetScript, TestScript, Credential...} 
PowerShell      Service                   PSDesiredStateConfiguration    1.1        {Name, BuiltInAccount, Credential, Dependencies...
PowerShell      User                      PSDesiredStateConfiguration    1.1        {UserName, DependsOn, Description, Disabled...}   
PowerShell      WaitForAll                PSDesiredStateConfiguration    1.1        {NodeName, ResourceName, DependsOn, PsDscRunAsC...
PowerShell      WaitForAny                PSDesiredStateConfiguration    1.1        {NodeName, ResourceName, DependsOn, PsDscRunAsC...
PowerShell      WaitForSome               PSDesiredStateConfiguration    1.1        {NodeCount, NodeName, ResourceName, DependsOn...} 
PowerShell      WindowsFeature            PSDesiredStateConfiguration    1.1        {Name, Credential, DependsOn, Ensure...}          
PowerShell      WindowsOptionalFeature    PSDesiredStateConfiguration    1.1        {Name, DependsOn, Ensure, LogLevel...}            
PowerShell      WindowsProcess            PSDesiredStateConfiguration    1.1        {Arguments, Path, Credential, DependsOn...}       
PowerShell      xSmbShare                 xSmbShare                      1.1.0.0    {Name, Path, ChangeAccess, ConcurrentUserLimit...}

If you experience problems installing resources, have a read of the MSDN Powershell Blog on How to Deploy and Discover Windows Powershell Desired State Configuration Resources.

Finding out about a Resource

List Installed DSC Resources

Get-DscResource

Get the properties for a resource

(Get-DscResource -Name File).Properties

Creating Resources

Sometimes it's necessary to create your own resources.

Please note that I couldn't get PowerShellGet working under Windows 7, which is used in the following example to install the xDSCResourceDesigner. It is possible to download it from GitHub and ensure the files are extracted to the appropriate path, e.g. C:\Program Files\WindowsPowerShell\Modules\xDSCResourceDesigner\1.5.0.0\.

Set-Up

Before you can begin creating your own resources, you will need to install the xDSCResourceDesigner module.

Installing xDSCResourceDesigner with WMF 4.0
  1. Download xDSCResourceDesigner from GitHub
  2. Extract the contents of the folder contained within the zip file to C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSCResources\xDSCResourceDesigner.

Once the module is installed, you can confirm it using Get-ChildItem:

> Get-ChildItem C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSCResources\xDSCResourceDesigner

    Directory: C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSCResources\xDSCResourceDesigner

Mode                LastWriteTime         Length Name                                                                                                                                                                                                                                                            
----                -------------         ------ ----                                                                                                                                                                                                                                                            
-a----       17/12/2014     18:09          17204 TechNetDocumentation-xDscResourceDesigner.html                                                                                                                                                                                                                  
-ar---       11/12/2014     14:13           1275 xDSCResourceDesigner.psd1                                                                                                                                                                                                                                       
-ar---       11/12/2014     14:13         103520 xDSCResourceDesigner.psm1                                                                                                                                                                                                                                       
-ar---       27/03/2014     09:33           8022 xDSCResourceDesigner.strings.psd1                                                                                                                                                                                                                               

And also check using Get-Module:

> Get-Module -listavailable | Select-String "xDSCResourceDesigner"
Installing xDSCResourceDesigner with WMF 5.0
Get-PackageProvider -Name NuGet -ForceBootstrap
Install-Module -Name xDSCResourceDesigner
Building Your New Resource

Using Your New Resource

Import the module containing your new resource into a DSC script and then simply use the new resource within the "Node" section.

Import-DscResource -ModuleName 'myDSCResources'

bnNssmService Unison
{
    NssmPath="C:\Unison\nssm-2.23\win64\nssm.exe"
    ServiceName="Unison"
    Ensure="Present"
    ServiceAdditionalArgs="-socket 874"
    ServicePath="C:\Unison\unison.exe"
    ServiceStartCondition="SERVICE_DEMAND_START"
    ServiceStopAction="Exit"
}

Further Info

Some of the references used in building my first resource:

Gotchas

Resources Not On Target Node

A DSC resource needs to be copied to a target host before it can be used. If you are using WMF 5.0 (Windows 8.1/Server 2012 r2 have WMF 4.0 pre-installed by default) and you use a library available from the PowerShell Gallery, then PowerShellGet should retrieve any PowerShell Gallery modules that you use almost automagically. Why 'almost'? That's because you need to install '''nuget-anycpu.exe''' on the target node first. That can be accomplished by

Get-PackageProvider -Name NuGet -ForceBootstrap

If you are using WMF 4.0 or a custom resource, then you will need to copy the module to the target host manually. We are using Group Policy to pre-stage everything needed for our DSC configuration to the '''C:\DSC''' folder on each target node. But you could, for example use a DSC script to pre-stage a target host, for example: Configuration PreStageIisWebServer { Import-DscResource –ModuleName ’PSDesiredStateConfiguration’

    Node "MyWebServer"
    {

        File bnDSCModuleReplace
        {
            SourcePath = "\\win2k12r2-dc1\dsc$\myDSCResources"
            DestinationPath = "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\myDSCResources"
            Recurse = $true
            Type = "Directory"
            Force= $true
            Ensure="Present"
        }        
    }
}
Set-Location -Path "D:\Code\infrastructure\Scripts\DesiredStateConfiguration\ManagedObjectFiles"
PreStageIisWebServer

Note that the source path needs to be a network share that the machine account on the target host has access too. See the "DSC Runs Under Local System Account" gotcha.

DSC Runs Under Local System Account

When DSC is applied to a target host, it runs on the target host under the local system account. This can make things like accessing network shares problematic without some pre-configuration. In order for DSC running on a target node to access a network share, you will need need to give the target hosts machine account the relevant permissions on that share. You can accomplish this from the command line on the server (or remotely via winrs or PsExec) as follows:

net share MyFolder=d:\dsc\staging /GRANT:>domain name<\>machine name<$,READ

Where >domain name< and >machine name< are subsituted for your Domain and your DSC target computer name.

The PSDesiredStateConfiguration File Resource

Does not copy files from source to destination when the source files already exist at the target location. Even if the source files have changed.

Exception Handling

In my experience so far, non-terminating powershell errors can turn into fugly uncaught exceptions. Especially when using "Test-TargetResource" within a custom resource and the test involves an unavoidable exception when the test fails. Either use $ErrorActionPreference="Stop" and handle the logic within a try-catch or use $ErrorActionPreference="SilentlyContinue" (N.B. once you have executed the potentially failing statements, you may want to set $ErrorActionPreference back to it's original value.

References

The DSC Book courtesy of Powershell.org[https://www.penflip.com/powershellorg/the-dsc-book]

The Technet DSC Blog Series, Part 1: Learning about DSC [http://blogs.technet.com/b/privatecloud/archive/2014/04/25/desired-state-configuration-blog-series-part-1-learning-about-dsc.aspx]