Introduction to PowerShell DSC on Windows Server 2022
PowerShell Desired State Configuration (DSC) is a management platform built into Windows PowerShell that enables you to define the desired state of your servers and continuously enforce that state. On Windows Server 2022, DSC is delivered through WMF 5.1 (Windows Management Framework), which is included in the OS by default. DSC is particularly valuable for automating server configuration, enforcing security baselines, managing roles and features, and ensuring configuration drift does not occur over time. This guide covers DSC architecture, Push and Pull modes, LCM configuration, built-in and community DSC resources, creating practical server hardening configurations, and monitoring compliance.
DSC Architecture and Core Concepts
DSC operates on a declarative model: you describe what a system should look like, not how to get there. A DSC Configuration is a PowerShell script block that uses Resources to describe the desired state. Resources are PowerShell modules that know how to test and set specific aspects of a system — a Windows Feature, a file, a registry key, a running service, or a local user account.
The Local Configuration Manager (LCM) is the engine on each node that applies and monitors DSC configurations. It runs as part of the WMI service and is configured separately from the node configurations themselves. When you compile a DSC Configuration, it produces a .mof (Managed Object Format) file, which is the serialized representation of the desired state. The LCM reads and applies the .mof.
DSC Push Mode: Start-DscConfiguration
In Push mode, you manually or programmatically push a compiled configuration .mof file to one or more target nodes from a management machine. This is the simplest mode to get started with and requires no infrastructure beyond WinRM connectivity to target servers.
First, write a configuration. This example ensures IIS is installed and the W3SVC service is running:
Configuration WebServerBaseline {
param (
[string[]]$ComputerName = 'localhost'
)
Import-DscResource -ModuleName PSDesiredStateConfiguration
Node $ComputerName {
WindowsFeature IIS {
Name = 'Web-Server'
Ensure = 'Present'
}
Service W3SVC {
Name = 'W3SVC'
State = 'Running'
StartupType = 'Automatic'
DependsOn = '[WindowsFeature]IIS'
}
}
}
# Compile the configuration to a .mof file
WebServerBaseline -ComputerName 'WebServer01'
Running this script creates a directory called WebServerBaseline containing WebServer01.mof. Push it to the target:
Start-DscConfiguration -Path .WebServerBaseline -ComputerName WebServer01 -Wait -Verbose -Force
The -Wait flag makes the command synchronous. -Verbose outputs detailed progress. -Force overrides any pending configurations on the target node.
LCM Configuration on Windows Server 2022
Before deploying configurations at scale, configure the LCM on each target node. The LCM settings control how often the node checks for new configurations, whether it applies or only reports on drift, and which Pull Server (if any) it contacts.
A common LCM configuration that sets the node to apply configurations and refresh every 30 minutes:
[DSCLocalConfigurationManager()]
Configuration LCMConfig {
Node 'localhost' {
Settings {
RefreshMode = 'Push'
ConfigurationMode = 'ApplyAndAutoCorrect'
RebootNodeIfNeeded = $true
RefreshFrequencyMins = 30
ActionAfterReboot = 'ContinueConfiguration'
}
}
}
LCMConfig
Set-DscLocalConfigurationManager -Path .LCMConfig -Verbose
The ConfigurationMode can be:
ApplyOnly— Apply configuration once and do not re-apply unless pushed again.ApplyAndMonitor— Apply once and report drift without correcting it.ApplyAndAutoCorrect— Apply and continuously correct any drift at each refresh cycle.
DSC Pull Mode with a Pull Server
In Pull mode, each target node polls a central DSC Pull Server for its configuration. This is the scalable approach for managing many servers. The Pull Server is an IIS-hosted OData web service that stores .mof files and DSC resource modules.
Configure the LCM for Pull mode. The node identifies its configuration by a ConfigurationID (a GUID) or a ConfigurationName (when using a Registration Key):
[DSCLocalConfigurationManager()]
Configuration PullClientConfig {
Node 'localhost' {
Settings {
RefreshMode = 'Pull'
ConfigurationMode = 'ApplyAndAutoCorrect'
RefreshFrequencyMins = 30
RebootNodeIfNeeded = $true
}
ConfigurationRepositoryWeb PullServer {
ServerURL = 'https://dscpull.corp.local:8080/PSDSCPullServer.svc'
RegistrationKey = '5acc7bce-9b19-45d3-a6e0-4f24c8e29a11'
ConfigurationNames = @('WebServerBaseline')
}
ResourceRepositoryWeb PullServerResources {
ServerURL = 'https://dscpull.corp.local:8080/PSDSCPullServer.svc'
RegistrationKey = '5acc7bce-9b19-45d3-a6e0-4f24c8e29a11'
}
ReportServerWeb ReportServer {
ServerURL = 'https://dscpull.corp.local:8080/PSDSCPullServer.svc'
RegistrationKey = '5acc7bce-9b19-45d3-a6e0-4f24c8e29a11'
}
}
}
PullClientConfig
Set-DscLocalConfigurationManager -Path .PullClientConfig -Verbose
Core DSC Resources in PSDesiredStateConfiguration
The PSDesiredStateConfiguration module is built into WMF 5.1 on Windows Server 2022 and provides the following foundational resources:
WindowsFeature — Install or remove Windows roles and features:
WindowsFeature Hyper-V {
Name = 'Hyper-V'
Ensure = 'Present'
IncludeAllSubFeature = $true
}
WindowsFeature Telnet {
Name = 'Telnet-Client'
Ensure = 'Absent'
}
File — Manage files and directories:
File ScriptsDirectory {
DestinationPath = 'C:Scripts'
Type = 'Directory'
Ensure = 'Present'
}
File DeploymentScript {
DestinationPath = 'C:Scriptsdeploy.ps1'
SourcePath = '\fileserverdscscriptsdeploy.ps1'
Ensure = 'Present'
Force = $true
}
Registry — Manage registry keys and values:
Registry DisableIPv6 {
Key = 'HKLM:SYSTEMCurrentControlSetServicesTcpip6Parameters'
ValueName = 'DisabledComponents'
ValueData = '255'
ValueType = 'Dword'
Ensure = 'Present'
}
Service — Manage Windows services:
Service RemoteRegistry {
Name = 'RemoteRegistry'
State = 'Stopped'
StartupType = 'Disabled'
}
Service WinRM {
Name = 'WinRM'
State = 'Running'
StartupType = 'Automatic'
}
User and Group — Manage local accounts:
User LocalAdmin {
UserName = 'SvcAccount'
Ensure = 'Present'
Password = (New-Object System.Management.Automation.PSCredential('SvcAccount', (ConvertTo-SecureString 'P@ssw0rd!' -AsPlainText -Force)))
PasswordNeverExpires = $true
Disabled = $false
}
Group Administrators {
GroupName = 'Administrators'
MembersToInclude = @('SvcAccount')
DependsOn = '[User]LocalAdmin'
}
DSC Configuration for Server Hardening
The following configuration applies a basic CIS-inspired hardening baseline to a Windows Server 2022 node. It disables unnecessary services, sets registry values for security, and removes optional features:
Configuration ServerHardening {
Import-DscResource -ModuleName PSDesiredStateConfiguration
Node 'localhost' {
# Disable legacy services
Service RemoteRegistry { Name = 'RemoteRegistry'; State = 'Stopped'; StartupType = 'Disabled' }
Service Spooler { Name = 'Spooler'; State = 'Stopped'; StartupType = 'Disabled' }
Service TlntSvr { Name = 'TlntSvr'; Ensure = 'Absent' }
# Remove Telnet client
WindowsFeature TelnetClient {
Name = 'Telnet-Client'
Ensure = 'Absent'
}
# Disable SMBv1
Registry DisableSMBv1 {
Key = 'HKLM:SYSTEMCurrentControlSetServicesLanmanServerParameters'
ValueName = 'SMB1'
ValueData = '0'
ValueType = 'Dword'
Ensure = 'Present'
}
# Require NTLMv2
Registry NTLMv2 {
Key = 'HKLM:SYSTEMCurrentControlSetControlLsa'
ValueName = 'LmCompatibilityLevel'
ValueData = '5'
ValueType = 'Dword'
Ensure = 'Present'
}
# Enable UAC
Registry EnableUAC {
Key = 'HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem'
ValueName = 'EnableLUA'
ValueData = '1'
ValueType = 'Dword'
Ensure = 'Present'
}
}
}
ServerHardening
Start-DscConfiguration -Path .ServerHardening -Wait -Verbose -Force
Community DSC Resource Modules
The PowerShell Gallery hosts many DSC resource modules that extend DSC beyond the built-ins. The most used are those from the xPSDesiredStateConfiguration, xWebAdministration, ComputerManagementDsc, and NetworkingDsc modules. Install them from PowerShell Gallery:
Install-Module -Name xWebAdministration -Force -AllowClobber
Install-Module -Name ComputerManagementDsc -Force
Install-Module -Name NetworkingDsc -Force
Install-Module -Name SecurityPolicyDsc -Force
Using xWebAdministration to create an IIS website:
Import-DscResource -ModuleName xWebAdministration
xWebsite DefaultSite {
Name = 'Default Web Site'
State = 'Stopped'
Ensure = 'Present'
PhysicalPath = 'C:inetpubwwwroot'
}
xWebsite AppSite {
Name = 'MyApp'
State = 'Started'
Ensure = 'Present'
PhysicalPath = 'C:inetpubmyapp'
BindingInfo = @(
MSFT_xWebBindingInformation {
Protocol = 'https'
Port = 443
CertificateThumbprint = 'ABCDEF1234567890ABCDEF1234567890'
CertificateStoreName = 'My'
}
)
}
Monitoring DSC Compliance
Once DSC is applied, you can monitor the compliance status of a node using the following commands:
# Get the last configuration status
Get-DscConfigurationStatus
# Get detailed results of the last DSC run
Get-DscConfigurationStatus -All | Select-Object Status, StartDate, DurationInSeconds, Type
# Test current compliance without applying changes
Test-DscConfiguration -Verbose
# Get a detailed compliance report
Test-DscConfiguration -Detailed
Test-DscConfiguration -Detailed returns an object with ResourcesInDesiredState and ResourcesNotInDesiredState properties, identifying exactly which resources have drifted.
Azure Guest Configuration as Cloud-Based DSC
Azure Guest Configuration (now part of Azure Policy) is the cloud-native evolution of DSC for Azure VMs and Arc-enabled servers. It uses DSC under the hood but integrates with Azure Policy for compliance reporting at scale. Assign a Guest Configuration policy to an Azure Policy definition, and Azure will report compliance across all VMs in your subscription.
To check the Guest Configuration extension status on a Windows Server 2022 Azure VM from PowerShell:
Get-AzVMExtension -ResourceGroupName "rg-prod" -VMName "vm-webserver01" -Name "AzurePolicyforWindows"
To create a custom Guest Configuration package, install the GuestConfiguration module:
Install-Module -Name GuestConfiguration -Force
New-GuestConfigurationPackage -Name 'ServerHardening' -Configuration .ServerHardeninglocalhost.mof -Type AuditAndSet -Force
Summary
PowerShell DSC on Windows Server 2022 provides a robust, built-in mechanism for configuration management. Push mode enables immediate, direct deployment from a management workstation. Pull mode scales to hundreds of servers through a central Pull Server. The LCM controls compliance mode, refresh frequency, and reboot behavior. Core resources handle features, files, registry, services, and accounts, while community modules extend coverage to IIS, networking, security policy, and more. The Get-DscConfigurationStatus and Test-DscConfiguration cmdlets provide visibility into compliance state. For cloud-hosted Windows servers, Azure Guest Configuration extends these capabilities to the Azure Policy compliance dashboard.