Infrastructure as Code (IaC) – Part 3 – Desired State Configuration (DSC)
Desired State Configuration (DSC) is a management platform in PowerShell that enables you to manage your IT and development infrastructure with configuration as code.
It was first released in PowerShell version 4.0 and can be used to automate the configuration of Windows and Linux operating systems.
No Active Directory and GPOs are needed.
By using traditional script based configuration, an administrator will set up all separate steps to accomplish a final desired configuration of a system. First the administrator needs to validate if the new configuration state is possibly or still present and therefore can be skipped. Also to roll back unintended configurations, all separate steps needs to be implemented.
By using Desired State Configuration (DSC) in contrast, an administrator will only describe declarative the final desired configuration of a system, DSC will then check itself the actual state of the system and which changes, additions or removals needs to be done to accomplish the new configuration and will execute them.
DSC runs within the Local Configuration Manager (LCM) engine which is a system module from Windows. The LCM runs on every target node and is responsible for parsing and enacting configurations that are sent to the node which should be configured.
For Linux the Open Management Infrastructure (OMI) stack acts as a similar counterpart to LCM on Windows systems and is designed for Linux and other Unix-like operating systems. OMI is often used in conjunction with configuration management tools like PowerShell DSC for cross-platform configuration management.
Introduction
Desired State Configuration (DSC) is a feature of PowerShell where modules are structured in a specific way to simplify configuration management in Linux and Windows machines.
DSC is a declarative language, where the state of a machine is described using a format that should be clear to understand even if the reader is not a subject matter expert. DSC is unique compared to imperative PowerShell script format, because the definition of an application environment is separate from the script logic that implements how it is delivered.
There are two primary components:
- Configurations are declarative PowerShell scripts that define instances of resources. Typically configurations define what to automate. Example scenarios include requirements for an application environment or operational/security standards.
- Resources contain the script functions that define how to automate. Resources always contain three methods, “Get”, “Test”, and “Set”. Example scenarios include how to update the contents of a file, how to run a utility that changes the state of a machine, or how to configure settings of an application.
As of version 7.2, the module PSDesiredStateConfiguration containing the DSC feature and must be installed as an independent component after you install PowerShell. Separating DSC into an independent module reduces the size of the PowerShell release package, and allows DSC to be upgraded on machines without also planning an upgrade of the PowerShell 7 installation.
Source: https://learn.microsoft.com/en-us/powershell/dsc/overview?view=dsc-3.0
Versions
There are three versions of DSC available:
- DSC 1.1 is the legacy version of DSC that originally shipped in Windows PowerShell 5.1.
- DSC 2.0 is the version of DSC that shipped in PowerShell 7.
With the release of PowerShell 7.2, the PSDesiredStateConfiguration module is no longer included in the PowerShell package. Separating DSC into its own module allows us to invest and develop DSC independent of PowerShell and reduces the size of the PowerShell package. Users of DSC will enjoy the benefit of upgrading DSC without the need to upgrade PowerShell, accelerating time to deployment of new DSC features. Users that want to continue using DSC v2 can download PSDesiredStateConfiguration 2.0.5 from the PowerShell Gallery. - DSC 3.0 is the new version of DSC. This version is a preview release that is still being developed. Users working with non-Windows environments can expect cross-platform features in DSC 3.0. DSC 3.0 is the version that is supported by the machine configuration feature of Azure Automanage.
The documentation for DSC has been moved to a new location so that we can manage the DSC version-specific information separate from the versions of PowerShell.
See the new documentation in Desired State Configuration 2.0.
Documentation
PSDesiredStateConfiguration v1.1
Desired State Configuration 2.0
PowerShell DSC 3.0 (Preview)
Microsoft Desired State Configuration v3 overviewDSCv3 leverages the PSDesiredStateConfiguration module to support compatibility with existing PowerShell based resources.
DSCv3 differs from PowerShell Desired State Configuration (PSDSC) in a few important ways:
- DSCv3 doesn’t depend on PowerShell. You can use DSCv3 without PowerShell installed and manage resources written in bash, python, C#, Go, or any other language.
- DSCv3 doesn’t include a local configuration manager. DSCv3 is invoked as a command. It doesn’t run as a service.
- Non-PowerShell resources define their schemas with JSON files, not MOF files.
- Configuration documents are defined in JSON or YAML files, not PowerShell script files.
Importantly, while DSCv3 represents a major change to the DSC platform, DSCv3 is able to invoke PSDSC Resources, including script-based and class-based DSC Resources, as they exist today. The configuration documents aren’t compatible, but all published PSDSC Resources are. You can use PSDSC resources in DSCv3 with both Windows PowerShell and PowerShell.
Resources
Desired State Configuration (DSC) Resources provide the building blocks for a DSC configuration. A resource exposes properties that can be configured (schema) and contains the PowerShell script functions that the Local Configuration Manager (LCM) calls to “make it so”.
A resource can model something as generic as a file or as specific as an IIS server setting. Groups of like resources are combined in to a DSC Module, which organizes all the required files in to a structure that is portable and includes metadata to identify how the resources are intended to be used.
Source: https://learn.microsoft.com/en-us/powershell/dsc/resources/resources?view=dsc-1.1#overview
More resources are for example users, groups, files, services, environment variables, processes and registry.
You can list all resources with the following commands on your machine.
PS C:> Get-DscResource
PS C:> Get-DscResource | ft ImplementationDetail, Name, Module, ModuleName
Here you will see a list by using PowerShell version 7.3.4 on a Windows Server 2019.
All resources have the following common properties:
Ensure=Present –> will ensure that a configuration will be applied if not already done.
Ensure=Absent –> will ensure that a configuration will be revoked if already applied
DependsOn=”[Ressourcentypename]RessourceName”
When you write Configurations, you add Resource blocks to configure aspects of a target Node. As you continue to add Resource blocks, your Configurations can grow quite large and cumbersome to manage. One such challenge is the applied order of your resource blocks. Typically resources are applied in the order they are defined within the Configuration. As your Configuration grows larger and more complex, you can use the DependsOn key to change the applied order of your resources by specifying that a resource depends on another resource.
Source: https://learn.microsoft.com/en-us/powershell/dsc/configurations/resource-depends-on?view=dsc-1.1
Local Configuration Manager (LCM)
The Local Configuration Manager (LCM) is the engine of Desired State Configuration (DSC). The LCM runs on every target node, and is responsible for parsing and enacting configurations that are sent to the node. It is also responsible for a number of other aspects of DSC, including the following.
- Determining refresh mode (push or pull).
- Specifying how often a node pulls and enacts configurations.
- Associating the node with pull service.
- Specifying partial configurations.
Source: https://learn.microsoft.com/en-us/powershell/dsc/managing-nodes/metaconfig?view=dsc-1.1
By executing the following command you can check the settings from the Local Configuration Manager (LCM).
Get-DscLocalConfigurationManager
RefreshFrequencyMins
The time interval, in minutes, at which the LCM checks a pull service to get updated configurations and checks local configuration for drift. The configuration is applied regardless of whether an update was downloaded. This value is ignored if the LCM is not configured in pull mode. The default value is 30.RefreshMode
Specifies how the LCM gets configurations. The possible values are “Disabled”, “Push”, and “Pull”.
Install new PowerShell Version
Recommended way to install PowerShell on Windows clients is to use the winget command.
Search for the latest version of PowerShell
PS C:> winget search Microsoft.PowerShellInstall PowerShell or PowerShell Preview using the id parameter
PS C:> winget install –id Microsoft.Powershell –source winget
PS C:> winget install –id Microsoft.Powershell.Preview –source winget
Best choice for Windows Servers and enterprise deployment scenarios is the MSI package.
Determine PowerShell version
PS C:> $PSVersionTable
Install Desired State Configuration (DSC)
PowerShell includes several Out-of-the-box resources for Desired State Configuration (DSC). The PSDesiredStateConfiguration module contains all of the OOB DSC resources available on your specific instance of PowerShell.
Below you will find a list of the OOB resources included in PowerShell 4.0 and a description of the resource’s capabilities.
Install Additional DSC Resources
https://learn.microsoft.com/en-us/powershell/dsc/configurations/install-additional-dsc-resources?view=dsc-1.1
The OOB resources allow a good starting point for common operations. If the OOB resources do not meet your needs, you can write your own Custom Resource. Before you write a custom resource to solve your problem, you should look through the vast number of DSC resources that have already been created by both Microsoft and the PowerShell community.
You can find DSC Resources on both the PowerShell Gallery and GitHub. You can also install DSC Resources directly from the PowerShell console using PowerShellGet.
PowerShellGet is a module with commands for discovering, installing, updating and publishing PowerShell artifacts like Modules, DSC Resources, Role Capabilities, and Scripts.
Source: https://learn.microsoft.com/en-us/powershell/module/powershellget/?view=powershellget-2.x
If you’re running PowerShell 6.0 or later, you already have a newer version of PowerShellGet and PackageManagement installed. You can upgrade to a newer version if necessary or install the preview release. You should always install the latest stable release.
Get-Module PowerShellGet, PackageManagement -ListAvailable
To install DSC Resources you can install the xPSDesiredStateConfiguration module with the following cmdlet.
Install-Module -Name xPSDesiredStateConfiguration
The xPSDesiredStateConfiguration module contains the same resources as the module PSDscResources but also includes bugfixes and new features, including additional resources. Some resources in this module use the prefix ‘x’ to not conflict with the older built-in resources in the Windows PowerShell PSDesiredStateConfiguration module and the PSDscResources module. The prefix ‘x’ has no other meaning and does not indicate that these are experimental resources.
This module is no longer comparable with the module PSDscResources as they are completely separate modules and they have a different lifecycle. The xPSDesiredStateConfiguration module surpasses the PSDscResources module in both features and bugfixes.
The module xPSDesiredStateConfiguration is supported by the DSC community who fixes bugs and adds features.
The module PSDscResources is supported by Microsoft and is meant to be 1:1 replacement for the built-in resources (in Windows PowerShell), with the exception for the File resource. For that reason new features are no longer being added to the PSDscResource module, and bugfixes must be approved (most likely through a Microsoft Support case) to be merged. If you require new features or missing bugfixes, please migrate to xPSDesiredStateConfiguration and request/add the features or bugfixes against this module.
Source: https://github.com/dsccommunity/xPSDesiredStateConfiguration
After installing the xPSDesiredStateConfiguration module you will see a bunch of additional resources when executing the Get-DscResoure cmdlet like shown below.
You can also list DSC resources from a specific module by enter the following command.
Get-DscResource -Module <ModulePrefix* or full name>
e.g.
Get-DscResource -Module PSDscResources
Install PowerShell Packages for DSC
In order to extend the range of functions (various configuration items on a machine) you can install additional packages for DSC.
https://www.powershellgallery.com/packages?q=DSC
All packages with an x as prefix are experimental and there will be no support for.
Get-Module vs. Get-InstalledModule
Get-InstalledModule lists all modules that were installed by using the Install-Module cmdlet (installed by PowerShellGet).
Get-Module shows modules from all locations mentioned in $env:PsModulePath location. List the modules imported in the current session or that can be imported from the PSModulePath.
The Get-Module cmdlet lists the PowerShell modules that have been imported, or that can be imported, into a PowerShell session. Without parameters, Get-Module gets modules that have been imported into the current session. The ListAvailable parameter is used to list the modules that are available to be imported from the paths specified in the PSModulePath environment variable ($env:PSModulePath).
Source: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-module
Get started with Desired State Configuration (DSC) for Windows
As already mentioned in the introduction, DSC is using resources which provides a building block for a DSC configuration.
Resources are for example users, groups, files, services, environment variables, processes and the registry. For these resources an administrator can define a final state (desired state configuration).
To define a state for these resources, we can use the resources properties, each of them have for example the following common properties:
- Ensure=Present –> will ensure that a configuration will be applied if not already done.
- Ensure=Absent –> will ensure that a configuration will be revoked if already applied.
- DependsOn=”[Ressourcentypename]RessourceName”
Typically resources are applied in the order they are defined within the Configuration. As your Configuration grows larger and more complex, you can use the DependsOn key to change the applied order of your resources by specifying that a resource depends on another resource.
Creating a configuration MOF document
To declare our configuration for the system, we need to create a DSC document which has the file type .mof for Managed Object Format (MOF).
Our DSC document starts with the configuration keyword followed by an arbitrary identifier. Next within a curly bracket is following a DSC node which represents the local computer or a remote computer. For the computer you can use the hostname or IP address.
Within a DSC node there can be one or several resource blocks. Each of these resource blocks are referring to a resource instance and defining its properties.
Each resource block starts with the name of the resource we want to configure and followed by an valid arbitrary identifier like before for the configuration block.
You can also leave out the DSC node and therefore the configuration will be applied by default to the local computer. So configuration { } can include just resource blocks but also several DSC nodes.
Below we will see a first example about how to create a DSC document and apply the configuration to a computer.
The Configuration will ensure a HelloWorld.txt file exists on your local machine. If you delete the file, DSC will recreate it the next time it updates.
In more advanced scenarios where multiple modules need to be imported so you can work with many DSC Resources in the same configuration, make sure to put each module in a separate line using Import-DscResource. This is easier to maintain in source control and required when working with DSC in Azure State Configuration.
Configuration HelloWorld { # Import the module that contains the File resource. Import-DscResource -ModuleName PsDesiredStateConfiguration Import-DscResource -ModuleName xWebAdministration
Configuration HelloWorld { # Import the module that contains the File resource. Import-DscResource -ModuleName PsDesiredStateConfiguration # The Node statement specifies which targets to compile MOF files for, when # this configuration is executed. Node localhost { # The File resource can ensure the state of files, or copy them from a # source to a destination with persistent updates. File HelloWorld { DestinationPath = "C:TempHelloWorld.txt" Ensure = "Present" Contents = "Hello World from DSC!" } } }
Save the file as HelloWorld.ps1.
The configuration calls one resources, the File resource. Resources do the work of ensuring that the target node is in the state defined by the configuration.
For a DSC configuration to be applied to a node, it must first be compiled into a MOF file. Running the configuration, like a function, will compile one .mof file for every Node defined by the Node block. In order to run the configuration, you need to dot source your HelloWorld.ps1 script into the current scope. For more information, see about_Scripts.
Dot source your HelloWorld.ps1 script by typing in the path where you stored it, after the . (dot, space). You may then, run your configuration by calling it like a function.
You could also invoke the configuration function at the bottom of the script so that you don’t need to dot-source.
Therefore we need to add the following line at the end of the DSC document.
HelloWorld -Output .Output
So the complete DSC document will now looks like this.
Configuration HelloWorld { # Import the module that contains the File resource. Import-DscResource -ModuleName PsDesiredStateConfiguration # The Node statement specifies which targets to compile MOF files for, when # this configuration is executed. Node localhost { # The File resource can ensure the state of files, or copy them from a # source to a destination with persistent updates. File HelloWorld { DestinationPath = "C:TempHelloWorld.txt" Ensure = "Present" Contents = "Hello World from DSC!" } } } HelloWorld -Output .Output
Now that you have the compiled MOF, you can apply the configuration to the target node (in this case, the local computer) by calling the Start-DscConfiguration cmdlet.
The Start-DscConfiguration cmdlet tells the Local Configuration Manager (LCM), the engine of DSC, to apply the configuration. The LCM does the work of calling the DSC resources to apply the configuration.
Use the code below to execute the Start-DSCConfiguration cmdlet. Specify the directory path where your localhost.mof is stored to the Path parameter. The Start-DSCConfiguration cmdlet looks through the directory specified for any <computername>.mof files. The Start-DSCConfiguration cmdlet attempts to apply each .mof file it finds to the computername specified by the filename (“localhost”, “server01”, “dc-02”, etc.).
Start-DscConfiguration -Path C:ScriptsHelloWorld -Verbose -Wait
Once the Start-DSCConfiguration cmdlet is complete, you should see a HelloWorld.txt file in the location you specified.
Apply the configuration to the machine
To allow DSC to run, Windows needs to be configured to receive PowerShell remote commands even when you’re running a localhost configuration. To easily configure your environment correctly, just run Set-WsManQuickConfig -Force in an elevated PowerShell Terminal.
Installation and configuration for Windows Remote Management
https://learn.microsoft.com/en-us/windows/win32/winrm/installation-and-configuration-for-windows-remote-management
You can apply Configuration documents (MOF files) to a machine with the Start-DscConfiguration cmdlet.
Start-DscConfiguration -Path ‘C:<path .mof files>’ -Wait -Verbose
Get the current state of the configuration
The Get-DscConfiguration cmdlet queries the current status of the machine and returns the current values for the configuration.
Get-DscConfiguration
If no configuration is applied to the machine, you will get the following error message.
If a configuration is applied you will see something like this.
Samples
Below we will see some samples of configuration scripts (DSC documents with the file extension *.ps), which will be used to generate a Managed Object Format (MOF) file we finally use to apply the configuration to the nodes.
Configurations are declarative PowerShell scripts
# Create the MOF file .<Configuration DSC Document>.ps1 # Publish (Push) the MOF file Start-DscConfiguration -Path .<Folder with .mof files> -Wait -Verbose -Force # This example specifies the Verbose parameter. Therefore, the command sends messages to the console as it proceeds. # The command includes the Wait parameter. Therefore, you cannot use the console until the command finishes all configuration tasks.
Start-DscConfiguration
https://learn.microsoft.com/en-us/powershell/module/psdesiredstateconfiguration/start-dscconfiguration?view=dsc-1.1
Crate a File
Configuration HelloWorld { # Import the module that contains the File resource. Import-DscResource -ModuleName PsDesiredStateConfiguration # The Node statement specifies which targets to compile MOF files for, when # this configuration is executed. Node localhost { # The File resource can ensure the state of files, or copy them from a # source to a destination with persistent updates. File HelloWorld { DestinationPath = "C:TempHelloWorld.txt" Ensure = "Present" Contents = "Hello World from DSC!" } } } HelloWorld -Output .Output
Create a Folder
Configuration CreateFolder { Import-DscResource -ModuleName PSDesiredStateConfiguration Node localhost { File CreateDataDir { DestinationPath = 'D:DSC TestingFolder1' Ensure = 'Present' Type = 'Directory' } } } CreateFolder -Output .Output
Create a Registry Entry
configuration CreateRegistryEntries { node localhost { Registry CreateFirstRegEntry { Ensure ="Present" Key ="HKEY_LOCAL_MACHINESOFTWAREblog.matrixpost.net" ValueName="FirstValueName" ValueData="123" } Registry CreateSecondRegEntry { Ensure ="Present" Key ="HKEY_LOCAL_MACHINESOFTWAREwww.matrixpost.net" ValueName="FirstValueName" ValueData="123" } } } CreateRegistryEntries -Output .Output
Adding Windows Features (Telnet Client)
The WindowsFeature resource in Windows PowerShell Desired State Configuration (DSC) provides a mechanism to ensure that roles and features are added or removed on a target node.
To determine the correct Name property, use the Get-WindowsFeature cmdlet like shown below.
Get-WindowsFeature | Where-Object displayname -Like ‘Telnet*’
The WindowsFeature resource is also included in the main module PsDesiredStateConfiguration as you can see below when listing all resources installed on the source node from which you will push the configuration.
So the configuration DSC document will looks like this.
Configuration TelnetClient { # Import the module that contains the WindowsFeature resource. Import-DscResource -ModuleName PsDesiredStateConfiguration # The Node statement specifies which targets to compile MOF files for, when # this configuration is executed. Node SQL2019.braincourt.de { # The WindowsFeature resource in Windows PowerShell Desired State Configuration (DSC) provides a # mechanism to ensure that roles and features are added or removed on a target node. WindowsFeature TelnetClient { Ensure = "Present" # Alternatively, to ensure the feature is uninstalled, set Ensure to "Absent" Name = "Telnet-Client" # Use the Name property from Get-WindowsFeature } } } TelnetClient -Output .Output
Pushing the configuration this time takes a little bit longer than for the previously samples which is obviously because installing a WindowsFeatures on the target node takes more time like creating a new file or registry entry.
Finally the Telnet Client feature is installed on the target node.
Adding Windows Roles (Network Policy and Access Services NPS)
To determine the correct Name property, we will use again the Get-WindowsFeature cmdlet like shown below.
Get-WindowsFeature | Where-Object displayname -Like ‘N*’
The WindowsRole resource is include in the WindowsFeature resource which himself is included in the main module PsDesiredStateConfiguration as we previously saw.
The configuration DSC document will looks like this, up to the Name property its the same as previously for the Windows Feature, so here its not different to configure roles.
Configuration Nps { # Import the module that contains the WindowsFeature resource. Import-DscResource -ModuleName PsDesiredStateConfiguration # The Node statement specifies which targets to compile MOF files for, when # this configuration is executed. Node SQL2019.braincourt.de { # The WindowsFeature resource in Windows PowerShell Desired State Configuration (DSC) provides a # mechanism to ensure that roles and features are added or removed on a target node. WindowsFeature Nps { Ensure = "Present" # Alternatively, to ensure the feature is uninstalled, set Ensure to "Absent" Name = "NPAS" # Use the Name property from Get-WindowsFeature } } } Nps -Output .Output
Finally the Network Policy and Access Services are installed on the target node.
Remove a Desired State Configuration (DSC)
This cmdlet removes that configuration document (.mof file) from the Windows PowerShell Desired State Configuration (DSC) configuration store and does additional cleanup.
$Session = New-CimSession -ComputerName “Server01” -Credential ACCOUNTSPattiFuller
Remove-DscConfigurationDocument -Stage Current -CimSession $Session
The first command creates a CIM session by using the New-CimSession cmdlet, and then stores the CimSession object in the $Session variable. The command prompts you for a password. For more information, type Get-Help New-CimSession.
A CIM session is a client-side object representing a connection to a local computer or a remote computer. The CIM session contains information about the connection, such as ComputerName, the protocol used, or various identifiers.
The second command removes the current configuration document for the computer specified in the CimSession stored in $Session.
The configuration documents (.mof files) are stored on the target node we pushed the configuration under the following path C:WindowsSystem32configuration.
In this case if no current configuration is applied to the target node, this folder on the target node will looks like this.
Now I will push a configuration from another node to the target node.
On the target node we pushed the configuration, there is now a new .mof file named Current.mof under the following path C:WindowsSystem32configuration.
In this path you can also depending on the configuration state see the following .mof files which are self-explaining:
- Previous.mof
- Pending.mof
To remove all of them on the target node you can execute the following cmdlet.
Remove-DscConfigurationDocument -Stage Current, Pending, Previous -Verbose
Desired State Configuration Pull Service
So far we just used the Push mode where we delivered the MOF file manually to the target node and its local LCM to enact it.
There is also a further and more complex method to deploy the MOF file automatically to the target nodes and is called Pull mode.
The Pull Server (Windows Feature DSC-Service) is a supported component of Windows Server however there are no plans to offer new features or capabilities.
It is recommended to begin transitioning managed clients to Azure Automation DSC (includes features beyond Pull Server on Windows Server) or one of the community solutions listed here.
Source: https://learn.microsoft.com/en-us/powershell/dsc/pull-server/pullserver
More about Azure Automation State you will find in my following post.
Before you enable Automation State Configuration, we would like you to know that a newer version of DSC is now generally available, managed by a feature of Azure Policy named guest configuration. The guest configuration service combines features of DSC Extension, Azure Automation State Configuration, and the most commonly requested features from customer feedback. Guest configuration also includes hybrid machine support through Arc-enabled servers.
Source: https://learn.microsoft.com/en-us/azure/automation/automation-dsc-getting-started
!!! Note !!!
Azure Policy Guest Configuration is now called Azure Automanage Machine Configuration.Source: https://learn.microsoft.com/en-us/azure/governance/machine-configuration/overview
More about Azure Automanage Machine Configuration you will find in my following post.
Series Summary
- Infrastructure as Code (IaC) – Part 1
- Infrastructure as Code (IaC) – Part 2 – Azure Resource Manager (ARM) templates
- Infrastructure as Code (IaC) – Part 3 – Desired State Configuration (DSC)
- Infrastructure as Code (IaC) – Part 4 – Azure Automation State
- Infrastructure as Code (IaC) – Part 5 – Azure Automanage Machine Configuration (formerly called Azure Policy Guest Configuration)
- Infrastructure as Code (IaC) – Part 6 – Terraform
Links
Windows Management Framework
https://learn.microsoft.com/en-us/powershell/scripting/windows-powershell/wmf/overviewDSC Resource Kit
https://github.com/powershell/dscresourcesConfiguring the Local Configuration Manager
https://learn.microsoft.com/en-us/powershell/dsc/managing-nodes/metaconfigPowerShell Desired State Configuration overview
https://learn.microsoft.com/en-us/powershell/dsc/overview?view=dsc-3.0