DSC - Desired State Configuration

Posted in automation on February 13, 2017 by Adrian Wyssmann ‐ 5 min read

During my work related to test environment provisioning I was stumbling over Desired State Configuration:

It is a new management platform in Windows PowerShell that enables deploying and managing configuration data for software services and managing the environment in which these services run.

Sounds pretty interesting isn’t it? I also recommend to read the DSC-Book @ Penflip.com or have a look at the source code at github. Let’s have a look on how it works…

Writing a DSC

DSC PowerShell scripts are are declarative scripts which define and configure instances of resources. They are idempotent, which means in whatever state the machine is, when applying the configuration LCM will ensure that the machine will end up in the exact state declared by the configuration. Here an example of such a script:

Configuration MyDscConfiguration {

    param(
        [string[]]$ComputerName="localhost"
    )

    Node $ComputerName {
        WindowsFeature FeatureExample {
            Ensure = "Present"
            Name =    "Telnet-Client"
        }
        WindowsFeature FeatureExample2 {
            Ensure = "Present"
            Name =    "Telnet-Server"
        }
        Service ServiceExample {
            Name = "TlntSvr"
            StartupType = "Manual"
            State = "Running"
        }
     }
} MyDscConfiguration

The outermost script block is the Configuration block. Embedded in the configuration block you can find Node blocks, which defined the nodes (computer, VM) to be configured. Within the node blocks there are one ore more Resource blocks which sets the properties for a resources belonging to the particular node. There are a lot of different resources and it’s corresponding properties available:

So in the above example We want to ensure that the “Telnet-Client” and “Terminal-Server” features are installed and the “Terminal-Server” is started. In order to get the appropriate “Names” you can get it by querying the available services with the “Get-WindowsFeature” cmdlet:

PS C:\Users\Administrator> Get-WindowsFeature

Display Name                                            Name                       Install State
------------                                            ----                       -------------
....
[ ] Telnet Client                                       Telnet-Client                  Available
[ ] Telnet Server                                       Telnet-Server                  Available
[ ] TFTP Client                                         TFTP-Client                    Available
...

Remark: The “Get-WindowsFeature” cmdlet is not available on all Windows versions cause it is either not available (e.g. Windows 7) or the related module needs to be loaded.

Once the DSC script is ready, you need to compile the script into and MOF document by calling the configuration file. This call will

  • Resolves all variables
  • Create a folder name of configuration in the current directory
  • Create a file named NodeName.mof in the new directory for each target node

In my case the file that is created is “localhost.mof” but by specifing “-ComputerName ‘TestWin2012-01′” I can override the parameter “ComputerName”:

PS D:\Workspaces\DSC> . .\MyDscConfiguration.ps1

    Directory: D:\Workspaces\DSC\MyDscConfiguration

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        08.02.2017     15:51       2526 localhost.mof

PS D:\Workspaces\DSC> .\MyDscConfiguration.ps1 -ComputerName 'TestWin2012-01'

    Directory: D:\Workspaces\DSC\MyDscConfiguration

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        08.02.2017     15:55       2530 TestWin2012-01.mof

PS D:\Workspaces\DSC> dir .\MyDscConfiguration


    Directory: D:\Workspaces\DSC\MyDscConfiguration


Mode                LastWriteTime     Length Name                                                                                                  
----                -------------     ------ ----                                                                                                  
-a---        08.02.2017     15:50       2520 localhost.mof                                                                                                                                                                           
-a---        08.02.2017     15:55       2530 TestWin2012-01.mof

The MSDN documentation show more interesting options like dependency handling and configuration of VMs on boot up.

Enacting Configurations

However, now that I have a compiled configuration I would like to run it. So my target machine “TestWin2012-01” does not have Telnet-Client or -Server installed so far. There are two modes for enacting configurations

  • Push mode: A user actively applies configuration to a target node by calling the Start-DscConfiguration cmdlet.
  • Pull  mode: Pull clients are configured to get their desired state configurations from a remote pull server

For the pull  mode to work, a server (web, smb) needs to be configured to host the service and the client node or the Local Configuration Manager - needs to be configured to pull the configurations from the pull server. The pull clients have a scheduled task that performs a periodic compliance check on the configuration on the node and if needed pulls the configurations and executes it. In this case I use the push mode

PS D:\Workspaces\DSC> Start-DscConfiguration -Path 'D:\Workspaces\DSC\MyDscConfiguration\'

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
11     Job11           Configuratio... Running       True            TestWin2012-01       Start-DscConfiguration...

So the Start-DscConfiguration cmdlet starts a background job and there is no visible feedback but you can query the job via the Get-Job cmdlet. Unfortunately in my case I only see that the job failed but there is no reason. So let’s run the job again in interactive mode:

PS D:\Workspaces\DSC> Start-DscConfiguration -Path 'D:\Workspaces\DSC\MyDscConfiguration\'  -Wait
WinRM cannot process the request. The following error occurred while using Kerberos authentication: Cannot find the computer TestWin2012-01.
Verify that the computer exists on the network and that the name provided is spelled correctly.
    + CategoryInfo          : NotSpecified: (root/Microsoft/...gurationManager:String) [], CimException
    + FullyQualifiedErrorId : HRESULT 0x80070035
    + PSComputerName        : TestWin2012-01

No surprise this does not work, I assume one need to set appropriate permissions. You may dig into detailed articles here, here and here. In the end I had to change the “TrustedNodes” configuration on the local machine.

PS D:\Workspaces\DSC> Start-DscConfiguration .\MyDscConfiguration TestWin2012-01 -Credential Administrator -Wait

PS D:\Workspaces\DSC> Enter-PSSession -ComputerName TestWin2012-01 -Credential Administrator

[TestWin2012-01]: PS C:\Users\Administrator\Documents>  Get-WindowsFeature

Display Name                                            Name                       Install State
------------                                            ----                       -------------
....
[X] Telnet Client                                       Telnet-Client                  Installed
[X] Telnet Server                                       Telnet-Server                  Installed
...

[TestWin2012-01]: PS C:\Users\Administrator\Documents> Get-Service TlntSvr

Status   Name               DisplayName
------   ----               -----------
Running  TlntSvr            Telnet

So this are just some basics and there is a lot more one can do with DSC. Also more interesting is the possibility to have a Pull-Server in place which make DSC configuration files available to target nodes when those nodes ask for them. I will cover this in another blog entry thus.