# Desired State Configuration

Topics

- What is Desired State Configuration?
- Host Requirements
- Why Use DSC?
- How to Use DSC?
  - Property Types
    - PSCredential
    - CimInstance Type
    - Arrays
  - Run As Another User
- Custom DSC Resources
  - Finding Custom DSC Resources
  - Installing a Custom Resource
- Examples
  - Extract a zip file
  - Create a directory
  - Interact with Azure
  - Setup IIS Website

## What is Desired State Configuration?

Desired State Configuration, or DSC, is a tool built into PowerShell that can be used to define a Windows host setup through code. The overall purpose of DSC is the same as Ansible, it is just executed in a different manner. Since Ansible 2.4, the `win_dsc` module has been added and can be used to leverage existing DSC resources when interacting with a Windows host.

More details on DSC can be viewed at DSC Overview.

## Host Requirements

To use the `win_dsc` module, a Windows host must have PowerShell v5.0 or newer installed. All supported hosts, except for Windows Server 2008 (non R2) can be upgraded to PowerShell v5.

Once the PowerShell requirements have been met, using DSC is as simple as creating a task with the `win_dsc` module.

## Why Use DSC?

DSC and Ansible modules have a common goal which is to define and ensure the state of a resource. Because of this, resources like the DSC File resource and Ansible `win_file` can be used to achieve the same result. Deciding which to use depends on the scenario.

Reasons for using an Ansible module over a DSC resource:

- The host does not support PowerShell v5.0, or it cannot easily be upgraded
- The DSC resource does not offer a feature present in an Ansible module. For example win_regedit can manage the `REG_NONE` property type, while the DSC `Registry` resource cannot
- DSC resources have limited check mode support, while some Ansible modules have better checks
- DSC resources do not support diff mode, while some Ansible modules do
- Custom resources require further installation steps to be run on the host beforehand, while Ansible modules are in built-in to Ansible
- There are bugs in a DSC resource where an Ansible module works

Reasons for using a DSC resource over an Ansible module:

- The Ansible module does not support a feature present in a DSC resource
- There is no Ansible module available
- There are bugs in an existing Ansible module

In the end, it doesn’t matter whether the task is performed with DSC or an Ansible module; what matters is that the task is performed correctly and the playbooks are still readable. If you have more experience with DSC over Ansible and it does the job, just use DSC for that task.

## How to Use DSC?

The `win_dsc` module takes in a free-form of options so that it changes according to the resource it is managing. A list of built in resources can be found at resources.

Using the Registry resource as an example, this is the DSC definition as documented by Microsoft:

    Registry [string] #ResourceName
    {
        Key = [string]
        ValueName = [string]
        [ Ensure = [string] { Enable | Disable }  ]
        [ Force =  [bool]   ]
        [ Hex = [bool] ]
        [ DependsOn = [string[]] ]
        [ ValueData = [string[]] ]
        [ ValueType = [string] { Binary | Dword | ExpandString | MultiString | Qword | String }  ]
    }

When defining the task, `resource_name` must be set to the DSC resource being used - in this case the `resource_name` should be set to `Registry`. The `module_version` can refer to a specific version of the DSC resource installed; if left blank it will default to the latest version. The other options are parameters that are used to define the resource, such as `Key` and `ValueName`. While the options in the task are not case sensitive, keeping the case as-is is recommended becuase it makes it easier to distinguish DSC resource options from Ansible’s `win_dsc` options.

This is what the Ansible task version of the above DSC Registry resource would look like:

    - name: use win_dsc module with the Registry DSC resource
      win_dsc:
        resource_name: Registry
        Ensure: Present
        Key: HKEY_LOCAL_MACHINE\SOFTWARE\ExampleKey
        ValueName: TestValue
        ValueData: TestData

### Property Types

Each DSC resource property has a type that is associated with it. Ansible will try to convert the defined options to the correct type during execution. For simple types like `[string]` and `[bool]` this is a simple operation, but complex types like `[PSCredential]` or arrays (like `[string[]]`) this require certain rules.

#### PSCredential

A `[PSCredential]` object is used to store credentials in a secure way, but Ansible has no way to serialize this over JSON. To set a DSC PSCredential property, the definition of that parameter should have two entries that are suffixed with `_username` and `_password` for the username and password respectively. For example:

    PsDscRunAsCredential_username: '{{ansible_user}}'
    PsDscRunAsCredential_password: '{{ansible_password}}'

    SourceCredential_username: AdminUser
    SourceCredential_password: PasswordForAdminUser

Note

You should set `no_log: true` on the task definition in Ansible to ensure any credentials used are not stored in any log file or console output.

#### CimInstance Type

A `[CimInstance]` object is used by DSC to store a dictionary object based on a custom class defined by that resource. Defining a value that takes in a `[CimInstance]` in YAML is the same as defining a dictionary in YAML. For example, to define a `[CimInstance]` value in Ansible:

    # [CimInstance]AuthenticationInfo == MSFT_xWebAuthenticationInformation
    AuthenticationInfo:
      Anonymous: no
      Basic: yes
      Digest: no
      Windows: yes

In the above example, the CIM instance is a representation of the class `MSFT_xWebAuthenticationInformation <https://github.com/PowerShell/xWebAdministration/blob/dev/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof>``_. This class accepts four boolean variables, ``Anonymous`, `Basic`, `Digest`, and `Windows`. The keys to use in a `[CimInstance]` depend on the class it represents. Please read through the documentation of the resource to determine the keys that can be used and the types of each key value. The class definition is typically located in the `<resource name>.schema.mof`.

#### Arrays

Simple type arrays like `[string[]]` or `[UInt32[]]` are defined as a list or as a comma separated string which are then cast to their type. Using a list is recommended because the values are not manually parsed by the `win_dsc` module before being passed to the DSC engine. For example, to define a simple type array in Ansible:

    # [string[]]
    ValueData: entry1, entry2, entry3
    ValueData:
    - entry1
    - entry2
    - entry3

    # [UInt32[]]
    ReturnCode: 0,3010
    ReturnCode:
    - 0
    - 3010

Complex type arrays like `[CimInstance[]]` (array of dicts), can be defined like this example:

    # [CimInstance[]]BindingInfo == MSFT_xWebBindingInformation
    BindingInfo:
    - Protocol: https
      Port: 443
      CertificateStoreName: My
      CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659
      HostName: DSCTest
      IPAddress: '*'
      SSLFlags: 1
    - Protocol: http
      Port: 80
      IPAddress: '*'

The above example, is an array with two values of the class `MSFT_xWebBindingInformation <https://github.com/PowerShell/xWebAdministration/blob/dev/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof>``_. When defining a ``[CimInstance[]]`, be sure to read the resource documentation to find out what keys to use in the definition.

### Run As Another User

By default, DSC runs each resource as the SYSTEM account and not the account that Ansible use to run the module. This means that resources that are dynamically loaded based on a user profile, like the `HKEY_CURRENT_USER` registry hive, will be loaded under the `SYSTEM` profile. The parameter PsDscRunAsCredential` is a parameter that can be set for every DSC resource force the DSC engine to run under a different account. As `PsDscRunAsCredential` has a type of `PSCredential`, it is defined with the `_username` and `_password` suffix.

Using the Registry resource type as an example, this is how to define a task to access the `HKEY_CURRENT_USER` hive of the Ansible user:

    - name: use win_dsc with PsDscRunAsCredential to run as a different user
      win_dsc:
        resource_name: Registry
        Ensure: Present
        Key: HKEY_CURRENT_USER\ExampleKey
        ValueName: TestValue
        ValueData: TestData
        PsDscRunAsCredential_username: '{{ansible_user}}'
        PsDscRunAsCredential_password: '{{ansible_password}}'
      no_log: true

## Custom DSC Resources

DSC resources are not limited to the built-in options from Microsoft. Custom modules can be installed to manage other resources that are not usually available.

### Finding Custom DSC Resources

You can use the PSGallery to find custom resources, along with documentation on how to install them on a Windows host.

The `Find-DscResource` cmdlet can also be used to find custom resources. For example:

    # find all DSC resources in the configured repositories
    Find-DscResource

    # find all DSC resources that relate to SQL
    Find-DscResource -ModuleName "*sql*"

Note

DSC resources developed by Microsoft that start with `x`, means the resource is experimental and comes with no support.

### Installing a Custom Resource

There are three ways that a DSC resource can be installed on a host:

- Manually with the `Install-Module` cmdlet
- Using the `win_psmodule` Ansible module
- Saving the module manually and copying it another host

This is an example of installing the `xWebAdministration` resources using `win_psmodule`:

    - name: install xWebAdministration DSC resource
      win_psmodule:
        name: xWebAdministration
        state: present

Once installed, the win_dsc module will be able to use the resource by referencing it with the `resource_name` option.

The first two methods above only work when the host has access to the internet. When a host does not have internet access, the module must first be installed using the methods above on another host with internet access and then copied across. To save a module to a local filepath, the following PowerShell cmdlet can be run:

    Save-Module -Name xWebAdministration -Path C:\temp

This will create a folder called `xWebAdministration` in `C:\temp` which can be copied to any host. For PowerShell to see this offline resource, it must be copied to a directory set in the `PSModulePath` environment variable. In most cases the path `C:\Program Files\WindowsPowerShell\Module` is set through this variable, but the `win_path` module can be used to add different paths.

## Examples

### Extract a zip file

    - name: extract a zip file
      win_dsc:
        resource_name: Archive
        Destination: c:\temp\output
        Path: C:\temp\zip.zip
        Ensure: Present

### Create a directory

    - name: create file with some text
      win_dsc:
        resource_name: File
        DestinationPath: C:\temp\file
        Contents: |
            Hello
            World
        Ensure: Present
        Type: File

    - name: create directory that is hidden is set with the System attribute
      win_dsc:
        resource_name: File
        DestinationPath: C:\temp\hidden-directory
        Attributes: Hidden,System
        Ensure: Present
        Type: Directory

### Interact with Azure

    - name: install xAzure DSC resources
      win_psmodule:
        name: xAzure
        state: present

    - name: create virtual machine in Azure
      win_dsc:
        resource_name: xAzureVM
        ImageName: a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201409.01-en.us-127GB.vhd
        Name: DSCHOST01
        ServiceName: ServiceName
        StorageAccountName: StorageAccountName
        InstanceSize: Medium
        Windows: True
        Ensure: Present
        Credential_username: '{{ansible_user}}'
        Credential_password: '{{ansible_password}}'

### Setup IIS Website

    - name: install xWebAdministration module
      win_psmodule:
        name: xWebAdministration
        state: present

    - name: install IIS features that are required
      win_dsc:
        resource_name: WindowsFeature
        Name: '{{item}}'
        Ensure: Present
      with_items:
      - Web-Server
      - Web-Asp-Net45

    - name: setup web content
      win_dsc:
        resource_name: File
        DestinationPath: C:\inetpub\IISSite\index.html
        Type: File
        Contents: |
          <html>
          <head><title>IIS Site</title></head>
          <body>This is the body</body>
          </html>
        Ensure: present

    - name: create new website
      win_dsc:
        resource_name: xWebsite
        Name: NewIISSite
        State: Started
        PhysicalPath: C:\inetpub\IISSite\index.html
        BindingInfo:
        - Protocol: https
          Port: 8443
          CertificateStoreName: My
          CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659
          HostName: DSCTest
          IPAddress: '*'
          SSLFlags: 1
        - Protocol: http
          Port: 8080
          IPAddress: '*'
        AuthenticationInfo:
          Anonymous: no
          Basic: yes
          Digest: no
          Windows: yes

See also

User Guide
  The documentation index
Working With Playbooks
  An introduction to playbooks
Best Practices
  Best practices advice
List of Windows Modules
  Windows specific module list, all implemented in PowerShell
User Mailing List
  Have a question? Stop by the google group!
irc.freenode.net
  #ansible IRC chat channel