PowerShell DSC: Introduction to Desired State Configuration

Configuring servers manually or through one-off scripts means configuration drift — machines diverge from their intended state over time. PowerShell Desired State Configuration (DSC) takes a different approach: you declare what a machine should look like, and PowerShell continuously ensures it stays that way. This post walks you through writing your first configuration, compiling it, applying it, and checking compliance.
Quick Answer / TL;DR
Write a Configuration block, call it to compile a MOF file, then apply with Start-DscConfiguration -Path .\ConfigName -Wait -Verbose. Test compliance with Test-DscConfiguration.
What Is DSC and Why Use It
DSC is a declarative configuration management platform built into PowerShell 5 and available on PowerShell 7 via the PSDesiredStateConfiguration module. You describe the desired state — which Windows features should be installed, what registry keys should exist, which services should be running — and DSC’s Local Configuration Manager (LCM) enforces that state. The two modes are Push (you apply the configuration) and Pull (machines check a central server). This post covers Push mode, which is the simpler starting point.
Write Your First Configuration
A Configuration block looks like a function but compiles to a Managed Object Format (MOF) file. Inside the block, you declare resources — each representing one configurable aspect of the system. The most common built-in resources are File, Registry, Service, and WindowsFeature.
# Define a DSC configuration
Configuration WebServerConfig {
param([string]$ComputerName = 'localhost')
Import-DscResource -ModuleName PSDesiredStateConfiguration
Node $ComputerName {
# Ensure IIS is installed
WindowsFeature IISInstall {
Ensure = 'Present'
Name = 'Web-Server'
}
# Ensure a directory exists
File WebRoot {
Ensure = 'Present'
Type = 'Directory'
DestinationPath = 'C:\inetpub\wwwroot\app'
}
# Ensure W3SVC service is running
Service W3SVC {
Name = 'W3SVC'
State = 'Running'
StartupType = 'Automatic'
DependsOn = '[WindowsFeature]IISInstall'
}
}
}
Compile to MOF File
Calling the configuration function compiles it into a MOF file in a folder named after the configuration. The MOF file is the actual artifact that the LCM reads — it is a text-based representation of the desired state. Inspect it to verify the resources are configured as intended.
# Compile the configuration to MOF
WebServerConfig -ComputerName 'webserver01' -OutputPath C:\DSC\WebServerConfig
# A folder is created with a .mof file named after the target node
Get-ChildItem C:\DSC\WebServerConfig
# View the MOF content
Get-Content C:\DSC\WebServerConfig\webserver01.mof
Directory: C:\DSC\WebServerConfig
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2024-03-15 1248 webserver01.mof
Apply Configuration with Start-DscConfiguration
Start-DscConfiguration applies the MOF to the target node. Use -Wait to block until the configuration is applied (rather than running as a background job) and -Verbose to see what each resource is doing. For remote targets, the LCM on the remote machine must be running and WinRM must be configured.
# Apply to local machine
Start-DscConfiguration -Path C:\DSC\WebServerConfig -Wait -Verbose -Force
# Apply to remote machine
Start-DscConfiguration -Path C:\DSC\WebServerConfig `
-ComputerName webserver01 -Credential (Get-Credential) `
-Wait -Verbose -Force
Built-In DSC Resources
The PSDesiredStateConfiguration module includes these core resources that cover most server configuration scenarios:
File— create/manage files and directoriesRegistry— manage registry keys and valuesService— control Windows servicesWindowsFeature— install/remove Windows roles and features (Server only)UserandGroup— manage local users and groupsPackage— install/remove software packagesScript— run arbitrary PowerShell as a DSC resource
# Registry resource example
Registry AppSettings {
Ensure = 'Present'
Key = 'HKLM:\SOFTWARE\MyApp'
ValueName = 'Version'
ValueData = '2.0'
ValueType = 'String'
}
# Service resource ensuring a service is stopped and disabled
Service PrintSpooler {
Name = 'Spooler'
State = 'Stopped'
StartupType = 'Disabled'
}
Test Configuration Compliance
Test-DscConfiguration checks whether the current system state matches the desired state without making any changes. It returns $true if compliant and $false if any resource is out of compliance. Use this in monitoring scripts to detect drift without risking unintended changes.
# Test compliance without making changes
$compliant = Test-DscConfiguration -Detailed
if ($compliant.InDesiredState) {
Write-Host 'System is compliant' -ForegroundColor Green
} else {
Write-Warning 'Configuration drift detected!'
$compliant.ResourcesNotInDesiredState | ForEach-Object {
Write-Warning " Non-compliant: $($_.ResourceId)"
}
}
# Get current applied configuration
Get-DscConfiguration
Common Errors and Fixes
- Configuration function name becomes MOF filename. When you compile a
Configuration WebServerConfig { Node server01 { } }, the output folder is namedWebServerConfigand the MOF file is namedserver01.mof. The node name (fromNodeblock), not the configuration name, becomes the MOF filename. This matters when targeting multiple machines — each node gets its own MOF. - LCM must be configured to apply push mode. The Local Configuration Manager on the target machine controls how DSC configurations are applied and refreshed. Check its current mode with
Get-DscLocalConfigurationManager. For push mode,RefreshModeshould bePush. Configure it with aLocalConfigurationManagerblock in aDSCLocalConfigurationManagerdecorated configuration.
Related Cmdlets / See Also
Wrapping Up
DSC shifts server configuration from imperative “do this” scripts to declarative “it should look like this” configurations. The workflow is always: write the Configuration block, compile to MOF, apply with Start-DscConfiguration, verify with Test-DscConfiguration. Start with the built-in resources and expand to community resources from the PowerShell Gallery as your needs grow.


