How to Set Up Windows Server 2012 R2 as a DSC Node

Once a DSC Pull Server is operational, the next step is configuring managed nodes to pull their configurations automatically. Each managed server runs a Local Configuration Manager (LCM) — the DSC engine built into PowerShell — that handles pulling configurations, applying them, and reporting compliance status back to the Pull Server. This guide covers all aspects of configuring a Windows Server 2012 R2 machine as a DSC pull node: LCM configuration, registration, applying configurations, handling reboots, and troubleshooting drift.

Prerequisites

– Windows Server 2012 R2 with PowerShell 4.0 minimum (WMF 5.0 recommended)
– Network connectivity to the DSC Pull Server on port 8080 or 443
– The Pull Server’s registration key (GUID string)
– Optionally, the Pull Server’s HTTPS certificate thumbprint
– Administrative rights on the node being configured

Step 1: Understand the Local Configuration Manager

Before making changes, review the current LCM state on the target node:

# View current LCM configuration
Get-DscLocalConfigurationManager

# Key settings to understand:
# ConfigurationMode     : ApplyAndMonitor (or ApplyAndAutoCorrect, ApplyOnly)
# RefreshMode           : Push (default) or Pull
# ConfigurationID       : GUID used to match configurations on the Pull Server
# RefreshFrequencyMins  : How often to pull (default 30 min)
# RebootNodeIfNeeded    : Whether LCM can auto-reboot
# AllowModuleOverwrite  : Whether newer module versions overwrite existing

# Check current DSC status
Get-DscConfigurationStatus

Step 2: Generate a ConfigurationID for the Node

In PowerShell 4.0 (WMF 4.0) Pull mode, each node is identified by a GUID called the ConfigurationID. The corresponding MOF on the Pull Server must be named with this GUID:

# Generate a unique GUID for this node
$configID = [System.Guid]::NewGuid().ToString()
Write-Host "Node ConfigurationID: $configID"
# Save this value — you need it to name the MOF on the Pull Server
# Example: 5cf20a8b-1234-5678-abcd-ef0123456789

Step 3: Configure the LCM for Pull Mode (PowerShell 4.0 / WMF 4.0)

Use a special DSC configuration targeting the LCM itself. The [DSCLocalConfigurationManager()] decorator distinguishes LCM meta-configurations from node configurations:

# WMF 4.0 LCM configuration syntax
Configuration LCMConfig_Pull_v4 {
    param(
        [string]$NodeName = 'localhost',
        [string]$PullServerURL = "http://dscpull01.corp.local:8080/PSDSCPullServer.svc",
        [string]$ConfigurationID,
        [string]$RegistrationKey
    )

    Node $NodeName {
        LocalConfigurationManager {
            ConfigurationMode             = "ApplyAndAutoCorrect"
            RefreshMode                   = "Pull"
            ConfigurationID               = $ConfigurationID
            DownloadManagerName           = "WebDownloadManager"
            DownloadManagerCustomData     = @{
                ServerUrl              = $PullServerURL
                AllowUnsecureConnection = "true"
            }
            RefreshFrequencyMins          = 30
            ConfigurationModeFrequencyMins = 15
            RebootNodeIfNeeded            = $true
            AllowModuleOverwrite          = $true
        }
    }
}

# Compile the LCM meta-configuration
$configID = "5cf20a8b-1234-5678-abcd-ef0123456789"  # Use the GUID from Step 2
LCMConfig_Pull_v4 -NodeName "localhost" `
    -ConfigurationID $configID `
    -PullServerURL "http://dscpull01.corp.local:8080/PSDSCPullServer.svc" `
    -OutputPath "C:DSCLCM"

# Apply the LCM configuration
Set-DscLocalConfigurationManager -Path "C:DSCLCM" -Verbose

Step 4: Configure the LCM for Pull Mode (PowerShell 5.0 / WMF 5.0)

WMF 5.0 introduces registration-based pull with improved syntax. Nodes register with the Pull Server using a registration key and can receive multiple partial configurations:

[DSCLocalConfigurationManager()]
Configuration LCMConfig_Pull_v5 {
    param(
        [string]$NodeName       = 'localhost',
        [string]$PullServerURL  = "http://dscpull01.corp.local:8080/PSDSCPullServer.svc",
        [string]$ReportServerURL= "http://dscpull01.corp.local:9080/PSDSCComplianceServer.svc",
        [string]$RegistrationKey= "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        [string]$ConfigName     = "WebServerBaseline"
    )

    Node $NodeName {
        Settings {
            RefreshMode                    = "Pull"
            ConfigurationMode              = "ApplyAndAutoCorrect"
            RefreshFrequencyMins           = 30
            ConfigurationModeFrequencyMins = 15
            RebootNodeIfNeeded             = $true
            AllowModuleOverwrite           = $true
            ActionAfterReboot              = "ContinueConfiguration"
            DebugMode                      = "None"
        }

        ConfigurationRepositoryWeb PullServer {
            ServerURL          = $PullServerURL
            RegistrationKey    = $RegistrationKey
            ConfigurationNames = @($ConfigName)
            AllowUnsecureConnection = $true
        }

        ResourceRepositoryWeb ModuleServer {
            ServerURL          = $PullServerURL
            RegistrationKey    = $RegistrationKey
            AllowUnsecureConnection = $true
        }

        ReportServerWeb ComplianceServer {
            ServerURL          = $ReportServerURL
            RegistrationKey    = $RegistrationKey
            AllowUnsecureConnection = $true
        }
    }
}

# Compile
LCMConfig_Pull_v5 -OutputPath "C:DSCLCM_v5"

# Apply
Set-DscLocalConfigurationManager -Path "C:DSCLCM_v5" -Verbose

# Verify
Get-DscLocalConfigurationManager

Step 5: Trigger an Immediate Pull and Apply

After configuring the LCM, trigger an immediate configuration check rather than waiting for the next refresh cycle:

# Force an immediate pull from the Pull Server
Update-DscConfiguration -Wait -Verbose

# Check what configuration was applied
Get-DscConfiguration

# Verify compliance — shows if current state matches desired state
Test-DscConfiguration -Verbose

# Get detailed status of the last run
$status = Get-DscConfigurationStatus
$status | Format-List *

# For detailed resource-level status
Get-DscConfigurationStatus | Select-Object -ExpandProperty ResourcesNotInDesiredState

Step 6: Handling Configuration Drift

With ApplyAndAutoCorrect mode, the LCM automatically corrects drift. Test this behavior and understand the event logs:

# Simulate drift: manually remove IIS (if WebServerBaseline is applied)
Remove-WindowsFeature -Name Web-Server

# Wait for LCM to detect and correct (RefreshFrequencyMins)
# Or trigger immediately:
Update-DscConfiguration -Wait -Verbose
# LCM should re-install IIS

# Monitor DSC events in real-time
Register-WmiEvent -Class Win32_NTLogEvent `
    -Query "SELECT * FROM Win32_NTLogEvent WHERE Logfile='Microsoft-Windows-Desired State Configuration/Operational' AND EventCode < 5000" `
    -Action { Write-Host "DSC Event: $($event.SourceEventArgs.NewEvent.Message)" }

# Review DSC operational log
Get-WinEvent -LogName "Microsoft-Windows-Desired State Configuration/Operational" `
    -MaxEvents 50 | Format-Table TimeCreated, LevelDisplayName, Message -Wrap

Step 7: Partial Configurations (WMF 5.0)

WMF 5.0 allows a node to receive multiple independent partial configurations that are merged. This lets different teams manage different aspects of a server:

[DSCLocalConfigurationManager()]
Configuration LCMConfig_Partial {
    Node "localhost" {
        Settings {
            RefreshMode   = "Pull"
            ConfigurationMode = "ApplyAndAutoCorrect"
        }

        ConfigurationRepositoryWeb PullServer {
            ServerURL       = "http://dscpull01.corp.local:8080/PSDSCPullServer.svc"
            RegistrationKey = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
        }

        PartialConfiguration WebRole {
            Description                     = "IIS web server configuration"
            ConfigurationSource             = @("[ConfigurationRepositoryWeb]PullServer")
            RefreshMode                     = "Pull"
        }

        PartialConfiguration SecurityBaseline {
            Description                     = "Security hardening configuration"
            ConfigurationSource             = @("[ConfigurationRepositoryWeb]PullServer")
            RefreshMode                     = "Pull"
            ExclusiveResources              = @("File","Registry")
        }
    }
}

LCMConfig_Partial -OutputPath "C:DSCLCM_Partial"
Set-DscLocalConfigurationManager -Path "C:DSCLCM_Partial" -Verbose

Step 8: Troubleshooting DSC Node Issues

# Common diagnostic commands

# 1. Check LCM state
Get-DscLocalConfigurationManager | Select-Object ConfigurationMode, RefreshMode, LCMState

# 2. Review last configuration run
Get-DscConfigurationStatus -All | Select-Object Type, Status, StartDate, DurationInSeconds | 
    Format-Table -AutoSize

# 3. Check for resources in error
Get-DscConfigurationStatus | Select-Object -ExpandProperty ResourcesNotInDesiredState |
    Select-Object ResourceId, Error

# 4. Force a consistency check without pulling
Start-DscConfiguration -UseExisting -Wait -Verbose

# 5. Remove all pending/current DSC configurations (reset)
Remove-DscConfigurationDocument -Stage Pending, Current, Previous -Force
Initialize-DiscoveryModule  # If modules are cached incorrectly

# 6. Reset the LCM entirely
Stop-DscConfiguration -Force
Remove-Item "C:WindowsSystem32configuration*.mof" -Force
Set-DscLocalConfigurationManager -Path "C:DSCLCM" -Force

Verification

# Full node health check
Write-Host "=== DSC Node Health Report ===" -ForegroundColor Cyan
Write-Host "LCM State:"
Get-DscLocalConfigurationManager | Select-Object LCMState, RefreshMode, ConfigurationMode | Format-List

Write-Host "Last Configuration Status:"
Get-DscConfigurationStatus | Select-Object Status, Mode, StartDate | Format-List

Write-Host "Compliance Check:"
$compliance = Test-DscConfiguration -Detailed
if ($compliance.InDesiredState) {
    Write-Host "Node IS in desired state" -ForegroundColor Green
} else {
    Write-Host "Node NOT in desired state. Non-compliant resources:" -ForegroundColor Red
    $compliance.ResourcesNotInDesiredState | ForEach-Object { Write-Host "  - $($_.ResourceId)" -ForegroundColor Yellow }
}

Summary

Configuring Windows Server 2012 R2 as a DSC pull node involves generating a ConfigurationID, setting up the LCM to point at the Pull Server, registering with the correct key, and letting the LCM handle configuration pulls and drift correction automatically. With ApplyAndAutoCorrect mode, the server becomes self-healing — any manual changes that deviate from the declared configuration are automatically reversed at the next LCM refresh. Combined with the Pull Server’s compliance reporting, this creates a continuously audited, continuously enforced infrastructure baseline across your entire server fleet.