Desired State Configuration

What is Desired State Configuration?

Desired State Configuration, or DSC, is a tool built into PowerShell that canbe used to define a Windows host setup through code. The overall purpose of DSCis the same as Ansible, it is just executed in a different manner. SinceAnsible 2.4, the win_dsc module has been added and can be used to leverageexisting 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 ornewer installed. All supported hosts, except for Windows Server 2008 (non R2) can beupgraded to PowerShell v5.

Once the PowerShell requirements have been met, using DSC is as simple ascreating 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 aresource. Because ofthis, resources like the DSC File resourceand Ansible win_file can be used to achieve the same result. Deciding which to use dependson 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 examplewin_regedit can manage the REG_NONE property type, while the DSCRegistry resource cannot
  • DSC resources have limited check mode support, while some Ansible modules havebetter checks
  • DSC resources do not support diff mode, while some Ansible modules do
  • Custom resources require further installation steps to be run on the hostbeforehand, 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 anAnsible module; what matters is that the task is performed correctly and theplaybooks are still readable. If you have more experience with DSC over Ansibleand 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 changesaccording to the resource it is managing. A list of built in resources can befound at resources.

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

  1. Registry [string] #ResourceName
  2. {
  3. Key = [string]
  4. ValueName = [string]
  5. [ Ensure = [string] { Enable | Disable } ]
  6. [ Force = [bool] ]
  7. [ Hex = [bool] ]
  8. [ DependsOn = [string[]] ]
  9. [ ValueData = [string[]] ]
  10. [ ValueType = [string] { Binary | Dword | ExpandString | MultiString | Qword | String } ]
  11. }

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

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

  1. - name: use win_dsc module with the Registry DSC resource
  2. win_dsc:
  3. resource_name: Registry
  4. Ensure: Present
  5. Key: HKEY_LOCAL_MACHINE\SOFTWARE\ExampleKey
  6. ValueName: TestValue
  7. ValueData: TestData

Property Types

Each DSC resource property has a type that is associated with it. Ansiblewill 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[]]) thisrequire certain rules.

PSCredential

A [PSCredential] object is used to store credentials in a secure way, butAnsible 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:

  1. PsDscRunAsCredential_username: '{{ansible_user}}'
  2. PsDscRunAsCredential_password: '{{ansible_password}}'
  3.  
  4. SourceCredential_username: AdminUser
  5. SourceCredential_password: PasswordForAdminUser

Note

You should set no_log: true on the task definition inAnsible to ensure any credentials used are not stored in any log file orconsole output.

CimInstance Type

A [CimInstance] object is used by DSC to store a dictionary object based ona 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:

  1. # [CimInstance]AuthenticationInfo == MSFT_xWebAuthenticationInformation
  2. AuthenticationInfo:
  3. Anonymous: no
  4. Basic: yes
  5. Digest: no
  6. Windows: yes

In the above example, the CIM instance is a representation of the classMSFTxWebAuthenticationInformation <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 onthe class it represents. Please read through the documentation of the resourceto determine the keys that can be used and the types of each key value. Theclass definition is typically located in the <resource name>.schema.mof.

Arrays

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

  1. # [string[]]
  2. ValueData: entry1, entry2, entry3
  3. ValueData:
  4. - entry1
  5. - entry2
  6. - entry3
  7.  
  8. # [UInt32[]]
  9. ReturnCode: 0,3010
  10. ReturnCode:
  11. - 0
  12. - 3010

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

  1. # [CimInstance[]]BindingInfo == MSFT_xWebBindingInformation
  2. BindingInfo:
  3. - Protocol: https
  4. Port: 443
  5. CertificateStoreName: My
  6. CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659
  7. HostName: DSCTest
  8. IPAddress: '*'
  9. SSLFlags: 1
  10. - Protocol: http
  11. Port: 80
  12. IPAddress: '*'

The above example, is an array with two values of the class MSFTxWebBindingInformation <https://github.com/PowerShell/xWebAdministration/blob/dev/DSCResources/MSFT_xWebsite/MSFT_xWebsite.schema.mof>``.When defining a ``[CimInstance[]], be sure to read the resource documentationto 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 accountthat Ansible use to run the module. This means that resources that are dynamicallyloaded based on a user profile, like the HKEYCURRENT_USER registry hive,will be loaded under the SYSTEM profile. The parameter_PsDscRunAsCredential` is a parameter that can be set for every DSC resourceforce the DSC engine to run under a different account. AsPsDscRunAsCredential 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 taskto access the HKEY_CURRENT_USER hive of the Ansible user:

  1. - name: use win_dsc with PsDscRunAsCredential to run as a different user
  2. win_dsc:
  3. resource_name: Registry
  4. Ensure: Present
  5. Key: HKEY_CURRENT_USER\ExampleKey
  6. ValueName: TestValue
  7. ValueData: TestData
  8. PsDscRunAsCredential_username: '{{ansible_user}}'
  9. PsDscRunAsCredential_password: '{{ansible_password}}'
  10. no_log: true

Custom DSC Resources

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

Finding Custom DSC Resources

You can use thePSGallery 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:

  1. # find all DSC resources in the configured repositories
  2. Find-DscResource
  3.  
  4. # find all DSC resources that relate to SQL
  5. Find-DscResource -ModuleName "*sql*"

Note

DSC resources developed by Microsoft that start with x, means theresource 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 usingwin_psmodule:

  1. - name: install xWebAdministration DSC resource
  2. win_psmodule:
  3. name: xWebAdministration
  4. state: present

Once installed, the win_dsc module will be able to use the resource by referencing itwith 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 installedusing the methods above on another host with internet access and then copiedacross. To save a module to a local filepath, the following PowerShell cmdletcan be run:

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

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

Examples

Extract a zip file

  1. - name: extract a zip file
  2. win_dsc:
  3. resource_name: Archive
  4. Destination: c:\temp\output
  5. Path: C:\temp\zip.zip
  6. Ensure: Present

Create a directory

  1. - name: create file with some text
  2. win_dsc:
  3. resource_name: File
  4. DestinationPath: C:\temp\file
  5. Contents: |
  6. Hello
  7. World
  8. Ensure: Present
  9. Type: File
  10.  
  11. - name: create directory that is hidden is set with the System attribute
  12. win_dsc:
  13. resource_name: File
  14. DestinationPath: C:\temp\hidden-directory
  15. Attributes: Hidden,System
  16. Ensure: Present
  17. Type: Directory

Interact with Azure

  1. - name: install xAzure DSC resources
  2. win_psmodule:
  3. name: xAzure
  4. state: present
  5.  
  6. - name: create virtual machine in Azure
  7. win_dsc:
  8. resource_name: xAzureVM
  9. ImageName: a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201409.01-en.us-127GB.vhd
  10. Name: DSCHOST01
  11. ServiceName: ServiceName
  12. StorageAccountName: StorageAccountName
  13. InstanceSize: Medium
  14. Windows: True
  15. Ensure: Present
  16. Credential_username: '{{ansible_user}}'
  17. Credential_password: '{{ansible_password}}'

Setup IIS Website

  1. - name: install xWebAdministration module
  2. win_psmodule:
  3. name: xWebAdministration
  4. state: present
  5.  
  6. - name: install IIS features that are required
  7. win_dsc:
  8. resource_name: WindowsFeature
  9. Name: '{{item}}'
  10. Ensure: Present
  11. with_items:
  12. - Web-Server
  13. - Web-Asp-Net45
  14.  
  15. - name: setup web content
  16. win_dsc:
  17. resource_name: File
  18. DestinationPath: C:\inetpub\IISSite\index.html
  19. Type: File
  20. Contents: |
  21. <html>
  22. <head><title>IIS Site</title></head>
  23. <body>This is the body</body>
  24. </html>
  25. Ensure: present
  26.  
  27. - name: create new website
  28. win_dsc:
  29. resource_name: xWebsite
  30. Name: NewIISSite
  31. State: Started
  32. PhysicalPath: C:\inetpub\IISSite\index.html
  33. BindingInfo:
  34. - Protocol: https
  35. Port: 8443
  36. CertificateStoreName: My
  37. CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659
  38. HostName: DSCTest
  39. IPAddress: '*'
  40. SSLFlags: 1
  41. - Protocol: http
  42. Port: 8080
  43. IPAddress: '*'
  44. AuthenticationInfo:
  45. Anonymous: no
  46. Basic: yes
  47. Digest: no
  48. Windows: yes

See also