How to Configure Windows Server 2019 with PowerShell DSC
PowerShell Desired State Configuration (DSC) is a configuration management platform built into Windows Server 2019 that enables declarative specification of server configuration. Instead of writing imperative scripts that perform actions step by step, you write a DSC configuration that describes the desired end state — which features should be installed, which services should be running, which files should exist — and DSC enforces that state. DSC is essential for automated server provisioning, configuration drift detection, and infrastructure-as-code workflows.
DSC Architecture Overview
DSC has two main components. The Local Configuration Manager (LCM) is an agent on each managed node that applies DSC configurations. DSC Resources are PowerShell modules that define how to configure specific aspects of a system (features, services, files, registry keys, etc.). Configurations are PowerShell scripts that produce MOF (Managed Object Format) files which the LCM reads and applies. DSC can operate in Push mode (you push configurations to nodes directly) or Pull mode (nodes retrieve configurations from a central pull server).
Installing DSC Resources
Windows Server 2019 includes built-in DSC resources for common tasks. Additional resources are available from the PowerShell Gallery, particularly the xPSDesiredStateConfiguration, ComputerManagementDsc, NetworkingDsc, and ServerManager resources.
# List built-in DSC resources
Get-DscResource | Select-Object Name, Module | Sort-Object Module
# Install community DSC resource modules from the PSGallery
Install-Module -Name ComputerManagementDsc -Force
Install-Module -Name NetworkingDsc -Force
Install-Module -Name xWebAdministration -Force
Install-Module -Name PSDesiredStateConfiguration -Force
# Verify installed resources
Get-DscResource | Where-Object { $_.Module -like "*Dsc*" } | Select-Object Name, Module
Writing a Basic DSC Configuration
A DSC configuration is a PowerShell function decorated with the [Configuration] keyword. Inside, you declare nodes and the desired state of resources on each node.
# Basic web server DSC configuration
Configuration WebServerConfig {
Import-DscResource -ModuleName PSDesiredStateConfiguration
Import-DscResource -ModuleName xWebAdministration
Node "WEBSVR01" {
# Ensure IIS is installed
WindowsFeature IIS {
Name = "Web-Server"
Ensure = "Present"
}
# Ensure ASP.NET 4.7 is installed
WindowsFeature ASPNET {
Name = "Web-Asp-Net45"
Ensure = "Present"
DependsOn = "[WindowsFeature]IIS"
}
# Ensure a directory exists
File WebRoot {
Type = "Directory"
DestinationPath = "C:inetpubmyapp"
Ensure = "Present"
}
# Ensure a web application is configured
xWebApplication MyApp {
Name = "MyApp"
WebAppPool = "DefaultAppPool"
PhysicalPath = "C:inetpubmyapp"
Website = "Default Web Site"
Ensure = "Present"
DependsOn = "[File]WebRoot"
}
# Ensure W3SVC service is running
Service W3SVC {
Name = "W3SVC"
State = "Running"
StartupType = "Automatic"
DependsOn = "[WindowsFeature]IIS"
}
}
}
# Compile the configuration to MOF
WebServerConfig -OutputPath "C:DSCMOF"
Configuring the Local Configuration Manager
Before applying configurations, configure the LCM on the target node. The LCM controls how often DSC checks configuration consistency, what to do when drift is detected (Apply, ApplyAndMonitor, or ApplyAndAutoCorrect), and other behaviour settings.
# LCM meta-configuration
[DSCLocalConfigurationManager()]
Configuration LCMConfig {
Node localhost {
Settings {
RefreshMode = "Push"
ConfigurationMode = "ApplyAndAutoCorrect"
RebootNodeIfNeeded = $true
ActionAfterReboot = "ContinueConfiguration"
RefreshFrequencyMins = 30
AllowModuleOverwrite = $true
}
}
}
# Compile the LCM configuration
LCMConfig -OutputPath "C:DSCLCMConfig"
# Apply the LCM meta-configuration
Set-DscLocalConfigurationManager -Path "C:DSCLCMConfig" -Verbose
# Verify the LCM settings
Get-DscLocalConfigurationManager
Applying a DSC Configuration (Push Mode)
In Push mode, you push the compiled MOF file directly to the target node using Start-DscConfiguration.
# Push configuration to a remote server
Start-DscConfiguration -Path "C:DSCMOF" -ComputerName "WEBSVR01" -Credential (Get-Credential) -Wait -Verbose
# Push configuration to the local machine
Start-DscConfiguration -Path "C:DSCMOF" -Wait -Verbose -Force
# Check the current DSC configuration status
Get-DscConfigurationStatus
# Test whether the current state matches the desired state
Test-DscConfiguration -Path "C:DSCMOF" -Verbose
Setting Up a DSC Pull Server
In Pull mode, managed nodes periodically contact a central pull server to retrieve their configurations. The pull server is an IIS-hosted web service. Set it up using the xPSDesiredStateConfiguration module.
Install-Module -Name xPSDesiredStateConfiguration -Force
Configuration PullServerSetup {
Import-DscResource -ModuleName xPSDesiredStateConfiguration
Import-DscResource -ModuleName PSDesiredStateConfiguration
Node "PULLSERVER01" {
WindowsFeature DSCService {
Name = "DSC-Service"
Ensure = "Present"
}
xDscWebService PullServer {
EndpointName = "PSDSCPullServer"
Port = 8080
PhysicalPath = "$env:SystemDriveinetpubPSDSCPullServer"
CertificateThumbPrint = "AllowUnencryptedTraffic" # Use a real cert in production
ModulePath = "$env:PROGRAMFILESWindowsPowerShellDscServiceModules"
ConfigurationPath = "$env:PROGRAMFILESWindowsPowerShellDscServiceConfiguration"
State = "Started"
Ensure = "Present"
DependsOn = "[WindowsFeature]DSCService"
}
}
}
PullServerSetup -OutputPath "C:DSCPullServer"
Start-DscConfiguration -Path "C:DSCPullServer" -Wait -Verbose -Force
Configuring Nodes to Pull from the Pull Server
[DSCLocalConfigurationManager()]
Configuration PullClientConfig {
Node "WEBSVR01" {
Settings {
RefreshMode = "Pull"
ConfigurationMode = "ApplyAndAutoCorrect"
RefreshFrequencyMins = 30
RebootNodeIfNeeded = $true
}
ConfigurationRepositoryWeb PullServer {
ServerURL = "http://pullserver01.corp.local:8080/PSDSCPullServer.svc"
RegistrationKey = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
ConfigurationNames = @("WebServerConfig")
AllowUnsecureConnection = $true # Use $false with HTTPS in production
}
}
}
PullClientConfig -OutputPath "C:DSCPullClient"
Set-DscLocalConfigurationManager -Path "C:DSCPullClient" -ComputerName "WEBSVR01" -Verbose
Monitoring DSC Configuration Compliance
# Check if a node is compliant with its desired configuration
Test-DscConfiguration -ComputerName "WEBSVR01" -Detailed
# Get the last configuration status
Get-DscConfigurationStatus -ComputerName "WEBSVR01" -All
# View DSC event logs
Get-WinEvent -LogName "Microsoft-Windows-Desired State Configuration-FileDownloadManager/Operational" -MaxEvents 20
Get-WinEvent -LogName "Microsoft-Windows-DSC/Operational" -MaxEvents 20 |
Select-Object TimeCreated, Id, Message | Format-List
Conclusion
PowerShell DSC on Windows Server 2019 provides a declarative, idempotent framework for server configuration management. Writing DSC configurations that specify the desired end state, compiling them to MOF files, and applying them via Push or Pull mode ensures consistent server builds and automatic drift correction. The rich ecosystem of community DSC resource modules from the PowerShell Gallery covers nearly every Windows Server configuration need, making DSC a practical foundation for infrastructure-as-code practices in Windows environments.