Desired State Configuration (DSC) is a server configuration management tool. With it, you can configure the server (make changes to the registry, copy files, install and remove components), monitor the current status of the settings and quickly roll back to the basic settings.DSC is interesting for those who follow the DevOps approach. This tool fits well with the paradigm of Infrastructure as a Code: developers can add their requirements to the configuration and include it in the version control system, and teams can deploy the code without using “manual” processes.Together with Stanislav Buldakov from RaiffeisenbankWe combined our experience with the DSC engine and divided it into 2 articles. In the first, we will analyze the basic principles of work and get acquainted with the features of use on practical examples:- “Unpack the box” with the DSC engine, see what resources are by default, and show where to get additional resources;
- Let's see how to describe the configuration in DSC;
- We will learn how the built-in agent Local Configuration Manager applies configurations on the server, show how it is configured using meta-configurations;
- let's move on to more complex configuration cases: partial configurations and stub configurations.
DSC is a lightweight and fast engine. For example, using it, you can install the .NET Framework 3.5 on virtual machines much faster. Here's what helps him speed up the service configuration process:- « » Windows PowerShell.
DSC PowerShell Windows Management Framework. Linux . , PowerShell. - , .
, , , . DSC. - , .
DSC , . .
Configurations are always performed sequentially, without conditions and branching. Therefore, briefly, the DSC operation algorithm looks like this:- Configure Local Configuration Manager (LCM) . This is the built-in agent that is responsible for applying configurations to the server. We tell him how the declared configurations should work and in what order.
- If additional resources are needed, install and connect them in advance.
- In a declarative form, we write the configuration order.
- We broadcast the configuration in the format of the MOF file.
- We send the configuration to the target freshly deployed or existing server.
- LCM receives the configuration (MOF file) plus instructions for setting up the LCM itself.
- The configuration is immediately applied by our team.
A simplified diagram of the DSC architecture.We will begin our acquaintance with the engine by studying the predefined resources. Next, try to write the configuration.DSC Resources
DSC resources are a kind of analogue to PowerShell modules. Any Windows server already has a predefined set of DSC resources; they are in the same directory as the PowerShell modules. The list can be obtained through the Get-DscResourse cmdlet. Here's what this list looks like on Windows 10 1809: PS C:\windows\system32> Get-DscResource | Sort-Object -Property Name | ft ImplementedAs, Name -a
ImplementedAs Name
------------- ----
PowerShell Archive
PowerShell Environment
Binary File
PowerShell Group
Composite GroupSet
Binary Log
PowerShell Package
PowerShell PackageManagement
PowerShell PackageManagementSource
Composite ProcessSet
PowerShell Registry
PowerShell Script
PowerShell Service
Composite ServiceSet
Binary SignatureValidation
PowerShell User
PowerShell WaitForAll
PowerShell WaitForAny
PowerShell WaitForSome
PowerShell WindowsFeature
Composite WindowsFeatureSet
PowerShell WindowsOptionalFeature
Composite WindowsOptionalFeatureSet
PowerShell WindowsPackageCab
PowerShell WindowsProcess
The names of the resources give an understanding of what they work with: - Archive - with packing and unpacking archives;
- Environment - with environment variables;
- File - with files;
- Group - with local user groups;
- Log - with logs;
- Package —– with software packages;
- Registry —– with registry keys and their status;
- Service - with services and their status;
- User - with local user accounts;
- WindowsFeature — Windows Server;
- WindowsProcess — Windows;
- Script — PowerShell- . 3 : SetScript — -, TestScript — , , GetScript — .
More often than not, out of the box DSC resources are not enough . In this case, you can write your own scripts for everything that goes beyond the standard module. In order not to reinvent the wheel, you can use DSC resources written by other developers. For example, from here https://github.com/PowerShell/DscResources or from PSGallery . How to install additional resources . We use the Install-Module cmdlet . Installing resources is simply copying resource files along one of the paths in the $ env: PSModulePath environment variable . Installed resources are not automatically connected during compilation, so later we will additionally connect them in the configuration itself.To use a resource, you need to install it locally and on the target server. In On-Premise infrastructures, a security policy typically prohibits Internet access for servers. In this case, the DSC server will not be able to load additional resources from external sources. To publish archives with modules, we deploy a local NuGet repository or a regular web server. You can install additional resources for the web server by unpacking the module into the C: \ Program Files \ WindowsPowerShell \ Modules \ directory.This is exactly what the Install-Module cmdlet does.In the second article, we will take a closer look at the difference between the setting for the Push and Pull modes. Simple configuration parsing
Configuration is a simple, consistent description of what needs to be done on the server. This is how a simple DSC configuration looks like: Configuration EnvironmentVariable_Path
{
param ()
Import-DscResource -ModuleName 'PSDscResources'
Node localhost
{
Environment CreatePathEnvironmentVariable
{
Name = 'TestPathEnvironmentVariable'
Value = 'TestValue'
Ensure = 'Present'
Path = $true
Target = @('Process', 'Machine')
}
}
}
EnvironmentVariable_Path -OutputPath:"C:\EnvironmentVariable_Path"
For her example, let's see what the configuration consists of.The Configuration block is a special type of PowerShell function that describes what we want to get. Inside the block contains: - param block with parameters that can be used internally;
- block with additional PowerShell calls. Here at the beginning of the configuration, we always run Import-Resource to connect additional resources;
- blocks with settings for specific Node $ servername servers .
Inside the Node block, we indicate which resources on a particular server we will configure. In the example above, this is creating an environment variable using a regular Environment resource.Let's look a little deeper and look at the syntax of a specific resource through the Get-DscResource -Name Environment -Syntax command:
PS C:\windows\system32> Get-DscResource -Name Environment -Syntax
Environment [String]
{
Name = [string]
[DependsOn = [string[]]]
[Ensure = [string]{ Absent | Present }]
[Path = [bool]]
[PsDscRunAsCredential = [PSCredential]]
[Value = [string]]
}
In this example: - Name - the name of the environment variable.
- In DependsOn, we specify the dependency on other resources. It is important to remember that the operation will not be performed until the resource specified here is completed.
- In Ensure, we specify the configuration conditions. If such a variable is absent, then we will create it; if it is present, then this resource will not be configured.
- The Path specifies whether the environment variable contain a path.
- In PsDscRunAsCredential specified credentials.
- Value - the value of the environment variable.
- The Target may be indicated in respect of whom the configuration is applied.
How to start compilation . We just call the configuration by its name with the necessary parameters. The result will be a mof file, which is further used by the DSC engine to configure a specific server: PS C:\windows\system32> EnvironmentVariable_Path -OutputPath:"C:\EnvironmentVariable_Path"
Directory: C:\EnvironmentVariable_Path
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 25.02.2020 14:05 2172 localhost.mof
Configure Local Configuration Manager
The local configuration manager is responsible for applying the configurations that we compiled into mof files. It is he who monitors the preservation of the state defined in the configuration. If the system leaves this state, LCM calls the code in the resources to restore the specified state. Let's see the Local configuration manager settings through Get-DscLocalConfigurationManager: PS C:\windows\system32> Get-DscLocalConfigurationManager
ActionAfterReboot : ContinueConfiguration
AgentId : 1FB3A2EE-57C9-11EA-A204-58A023EF3A48
AllowModuleOverWrite : False
CertificateID :
ConfigurationDownloadManagers : {}
ConfigurationID :
ConfigurationMode : ApplyAndMonitor
ConfigurationModeFrequencyMins : 15
Credential :
DebugMode : {NONE}
DownloadManagerCustomData :
DownloadManagerName :
LCMCompatibleVersions : {1.0, 2.0}
LCMState : Idle
LCMStateDetail :
LCMVersion : 2.0
StatusRetentionTimeInDays : 10
SignatureValidationPolicy : NONE
SignatureValidations : {}
MaximumDownloadSizeMB : 500
PartialConfigurations :
RebootNodeIfNeeded : False
RefreshFrequencyMins : 30
RefreshMode : PUSH
ReportManagers : {}
ResourceModuleManagers : {}
PSComputerName :
- RefreshMode contains the LCM operating mode - Push or Pull. We will talk more about modes in the second article.
- ConfigurationMode shows the current configuration application mode. In our case, it is ApplyAndMonitor - apply and track changes. ApplyOnly modes are also available (LCM will not track configuration changes) and ApplyAndAutocorrect modes (LCM will not only track changes, but also roll them back to the base configuration).
- RebootNodeIfNeeded - can reboot the server after the configuration is completed, if necessary to apply the settings.
- ConfigurationModeFrequencyMins - Fixes how often LCM will check for configuration changes.
Change LCM settings in meta-configuration. Here is her example:
Configuration LCMConfiguration
{
Node Localhost
{
LocalConfigurationManager
{
RebootNodeIfNeeeded = $True
}
}
}
LCMConfiguration
Same for the latest version of WMF with comments:
[DSCLocalConfigurationManager()]
Configuration LCMConfiguration
{
param
(
[string[]]$Server = "localhost"
)
Node $Server
{
Settings
{
RebootNodeIfNeeded = $True
RefreshMode = 'Push'
RefreshFrequencyMins = 30
}
}
}
LCMConfiguration -Server "localhost" -OutputPath "C:\DSC\MetaConfigurations\EnvironmentVariable_Path\"
Features metaconfiguration . When writing a metaconfiguration, we use the same blocks as for a regular DSC configuration. The exception is the LocalConfigurationManager (v4) internal block or the DSCLocalConfigurationManager (v5) attribute for a specific server. They describe all the necessary settings. The metaconfiguration is also compiled into a mof file, but to use it, the Set-DSCLocalConfigurationManager cmdlet is used, and not Start-DSCConfiguration. PS C:\windows\system32> LCMConfiguration -OutputPath C:\EnvironmentVariable_Path\
Directory: C:\EnvironmentVariable_Path
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 26.02.2020 20:05 1016 Localhost.meta.mof
PS C:\windows\system32> Set-DscLocalConfigurationManager -Path C:\EnvironmentVariable_Path\
PS C:\windows\system32> Get-DscLocalConfigurationManager
…
RebootNodeIfNeeded : True
…
Theoretically, nothing prevents us from combining the configuration of LCM and conventional resources within the same configuration. But for simplicity, it is recommended that the spelling and application of configuration and metaconfiguration be separated.Partial Configurations
Partial Configurations - several configurations that are executed sequentially one after another. They are useful when several teams work on the service. Each of the commands indicates the settings for its part of the service, and the partial configuration then applies all the settings sequentially. In LCM settings, we specify partial configurations in PartialConfigurations . In partial configurations, we must consider the straightforward DSC logic. The engine does not allow branching, so additional resources are needed to fulfill various conditions. We will analyze this with a few examples. Suppose we want to guaranteedly deliver the configuration to the server and proceed according to the following algorithm:- First, check that the necessary modules are installed on the server.
- We perform the configuration, which will bring the server to the desired state.
Here's what a metaconfiguration looks like with several consecutive configurations inside:
[DSCLocalConfigurationManager()]
configuration MetaPushConfig
{
param
(
[ValidateNotNullOrEmpty()]
[string] $NodeName = 'localhost'
)
Node $NodeName
{
PartialConfiguration ModulesDownloadConfig
{
Description = 'Download and install modules'
RefreshMode = 'Push'
}
PartialConfiguration ServerOSConfig
{
DependsOn = "[PartialConfiguration]ModulesDownloadConfig"
Description = 'Configuration'
RefreshMode = 'Push'
}
Settings
{
RefreshMode = 'Push'
RefreshFrequencyMins = 30
RebootNodeIfNeeded = $true
}
}
}
MetaPushConfig -NodeName "NewServer.contoso.com" -OutputPath c:\DSC\MetaConfigurations
$cred = (Get-Credential -UserName Administrator -Message "Enter admin credentials")
Set-DscLocalConfigurationManager -ComputerName "NewServer.contoso.com" -Credential $cred -Path "c:\DSC\MetaConfigurations" -Verbose -Force
Publish-DscConfiguration c:\DSC\Configurations\ModulesDownloadConfig -ComputerName "NewServer.contoso.com" -Credential $cred -Force
Publish-DscConfiguration c:\DSC\Configurations\ServerOSConfig -ComputerName "NewServer.contoso.com" -Credential $cred -Force
Start-DscConfiguration -UseExisting -ComputerName "NewServer.contoso.com" -Credential $cred -Force -Verbose
The first part of the configuration says Download and install module s: download and install the necessary resources. The second part of ServerOSConfig brings the server to the desired state. What are the nuances with DSC straightforwardness here: - If the first part of the configuration initially returned FALSE and completed completely, then LCM will not go to the second configuration. According to the DSC logic, first you need to bring the server to the first state described.
How to treat: run the configuration twice or automate the entire process in a script. - If the server after installing any component requires a reboot, then the configuration will not go further until we ourselves reboot the server. Even if we tell LCM that RebootNodeIfNeeeded = $ True, the agent will wait for our solution during configuration.
How to treat: the xPendingReboot resource comes to the rescue , which controls the registry key upon reboot. This resource restarts the server for us.
Here is an example configuration for downloading and installing resources in the “bloody enterprise” scenario, when the server does not have Internet access. It assumes the presence of a web server, where pre-downloaded resources are available to everyone via the http protocol.
Configuration ModulesDownloadConfig
{
param
(
[string[]]$Server
)
Import-DscResource -ModuleName "PSDesiredStateConfiguration"
Node $Server
{
Registry DisableIEESC-Admin {
Key = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}"
ValueName = "IsInstalled"
Ensure = "Present"
ValueData = 0
ValueType = "DWORD"
}
Registry DisableIEESC-User {
Key = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}"
ValueName = "IsInstalled"
Ensure = "Present"
ValueData = "0"
ValueType = "DWORD"
}
File CreateDistribDir {
Ensure = "present"
DestinationPath = "C:\Install\PSModules"
Type = "Directory"
}
Script NetworkingDscDownLoad {
SetScript = { Invoke-WebRequest -Uri "http://repo.contoso.com/repo/modules/NetworkingDsc.zip" -OutFile "C:\Install\PSModules\NetworkingDsc.zip" }
GetScript = { return @{ Result = Test-Path "C:\Install\PSModules\NetworkingDsc.zip"
GetScript = $GetScript; SetScript = $SetScript; TestScript = $TestScript
}
}
TestScript = { Test-Path "C:\Program Files\WindowsPowerShell\Modules\NetworkingDsc" }
}
Archive UnpackNetworkingDsc {
Ensure = "Present"
DependsOn = "[Script]NetworkingDscDownLoad"
Path = "C:\Install\PSModules\NetworkingDsc.zip"
Destination = "C:\Program Files\WindowsPowerShell\Modules\"
}
Script ComputerManagementDscDownLoad {
SetScript = { Invoke-WebRequest -Uri "http://repo.contoso.com/repo/modules/ComputerManagementDsc.zip" -OutFile "C:\Install\PSModules\ComputerManagementDsc.zip" }
GetScript = { return @{ Result = Test-Path "C:\Install\PSModules\ComputerManagementDsc.zip"
GetScript = $GetScript; SetScript = $SetScript; TestScript = $TestScript
}
}
TestScript = { Test-Path "C:\Program Files\WindowsPowerShell\Modules\ComputerManagementDsc" }
}
Archive UnpackComputerManagementDsc {
Ensure = "Present"
DependsOn = "[Script]ComputerManagementDscDownLoad"
Path = "C:\Install\PSModules\ComputerManagementDsc.zip"
Destination = "C:\Program Files\WindowsPowerShell\Modules\"
}
Script xPendingRebootDownLoad {
SetScript = { Invoke-WebRequest -Uri "http://repo.contoso.com/repo/modules/xPendingReboot.zip" -OutFile "C:\Install\PSModules\xPendingReboot.zip" }
GetScript = { return @{ Result = Test-Path "C:\Install\PSModules\xPendingReboot.zip"
GetScript = $GetScript; SetScript = $SetScript; TestScript = $TestScript
}
}
TestScript = { Test-Path "C:\Program Files\WindowsPowerShell\Modules\xPendingReboot" }
}
Archive UnpackxPendingReboot {
Ensure = "Present"
DependsOn = "[Script]xPendingRebootDownLoad"
Path = "C:\Install\PSModules\xPendingReboot.zip"
Destination = "C:\Program Files\WindowsPowerShell\Modules\"
}
}
}
About security
The fat minus of DSC on the ground is the lack of Run As Accounts. This mechanism safely stores accounts in the form of username + "salt hash of the password" and palm off them to the service, which is responsible for authentication. Without it, DSC cannot manage accounts on behalf of another service. And if we need to authenticate under an account with special privileges, the automation process is greatly complicated. For example, this will be the case when entering the server into the domain.Everything at our disposal:- credentials are stored in Plain Text,
- encrypted credentials only work on the PC where they were generated.
In practice, there are several solutions. "Stubs" are good when predictability of server behavior must be ensured.We do a “stub” after the server configuration in several cases, if we used:- reboot (xPendingReboot resource)
- credential transfer
- other resources that may affect the server’s performance regarding unplanned reboots or security.
To do this, create and republish configurations WITHOUT blocks containing the xPendingReboot resource and configurations with credentials.This approach applies only to the Push scenario, since Pull is fairly straightforward and does not imply a configuration change on the fly. In the next article frombuldakovWe will take a closer look at the settings and features of working in the Push and Pull modes.And also come to discuss the nuances of DSC technology and the boundaries of its application on May 28 at 18.00 at the first online meeting of the Raiffeisenbank DGTL Communications community. Also at the meeting we’ll talk about how to make ELK and Exchange friends and what Microsoft Endpoint Manager can do in device management. Here is the registration for the mitap .