Configuring Virtual Machines Using Desired State Configuration - Part 1 - Introduction

With the ever evolving world of cloud, organizations need to deploy and configure resources faster and in a more controlled manner. Although Azure ARM and other tools like Terraform provide the ability to manage all the resources as code and just submit deployment jobs, we sometimes need a bit more, especially when it comes to virtual machines. Microsoft Desired State Configuration is a technology that helps to approach the guest operating system of virtual machines is a similar manner.

So, what is DSC exactly? As per Microsoft Docs, DSC is a management platform in PowerShell that enables you to manage your IT and development infrastructure with configuration as code. But what does that mean to the everyday consultant or administrator? With DSC, you are able to describe the configuration to be applied to a virtual machine and then the engine will take any steps necessary in order for the machine to reach that state. DSC can also manage configuration drift and not only apply configurations but also auto-correct the state of the machine when needed.

Let's take for example a Windows Server machine that right after it has been deployed we have to add a role and some features to it, say IIS and copy some website files. An administrator would have to login to the machine or use Server Manager in order to add the roles and features and copy over the files. With DSC, we only have to author a configuration once and then just apply it to the machines.

Below is a small configuration sample that performs this exact operation:

Configuration WebApp001 {
    # Import the module that contains the resources we're using.
    Import-DscResource -ModuleName PsDesiredStateConfiguration

    # The Node statement specifies which targets this configuration will be applied to.
    Node 'localhost' {

        # The first resource block ensures that the Web-Server (IIS) feature is enabled.
        WindowsFeature WebServer {
            Ensure = "Present"
            Name   = "Web-Server"

        # The second resource block ensures that the website content copied to the website root folder.
        File WebsiteContent {
            Ensure = 'Present'
            SourcePath = '\\fileserver\dsc\WebApp001\iisstart.htm'
            DestinationPath = 'c:\inetpub\wwwroot'
            Checksum = "modifiedDate"
            Force = $true
            MatchSource = $true
            DependsOn = '[WindowsFeature]WebServer'

There are two steps in order to apply the configuration to a machine. First we need to create what is called a MOF file. The DSC engine running on the computer to be configured understands MOF files, so we need to compile the script we have and then push it using the Start-DscConfiguration cmdlet.

To do this we need to dot source the file and then execute the configuration. In my case the file name is "WebApp001.ps1" and the name of the configuration "WebApp001" as declared in the script.

Let's see how it went!

The first two commands load and compile the configuration and the third one pushes it to the node.

The parameters used to start the configuration job are:

  • the "-Path" with the path of the directory that was created when the configuration was compiled - usually at the current path named after the configuration,
  • the "-Wait" in order to follow the process and not just push the configuration and
  • the "-Verbose" to get the full output of the command

Going through the output we see that the LCM tested for the existence of the WebServer role and since it was not found it proceeded with the installation. The page file was next due to the fact that we had specified in the configuration that it depends on the WebServer role (line 22). Although the file existed as part of the default installation of IIS the configuration dictated that is should be compared to the source, thus the file was overwritten.

Following the successfull execution, we should be having a working IIS installed and a page copied over to the root of the default site.

Exactly what we were looking for!

In the next article of the series we'll focus on the LCM and the various configuration options it has so stay tuned!

All of the scripts used in this post are available in my Github repository over here.

Related Articles
    Part 1 - Intruduction

Popular posts from this blog

Domain Controller Machine Password Reset

Configuring a Certificate on Exchange Receive Connector

Verbose Parameter Passing to cmdlet inside Function