PowerShell DSC v3: Getting Started with Configuration Resources
─□✕

PowerShell DSC v3: Getting Started with Configuration Resources

PowerShell Tips Editor 5 min read
PowerShell DSC v3: Getting Started with Configuration Resources

Desired State Configuration has been part of the PowerShell ecosystem since version 4, but DSC v3 is not an incremental update — it is a ground-up architectural rewrite. The Local Configuration Manager is gone. Resources are now standalone executables. Configurations are written in JSON or YAML rather than PowerShell syntax. Most importantly, DSC v3 runs on PowerShell 7 across Windows, Linux, and macOS, making consistent configuration management across a heterogeneous fleet genuinely practical for the first time.

Installing DSC v3 on Windows and Linux

DSC v3 ships as a standalone binary (dsc.exe on Windows, dsc on Linux) distributed through GitHub Releases and the Microsoft package feed. It does not install through Install-Module because it is not a PowerShell module at all.

On Windows, download the latest MSI from the DSC releases page or use winget:

# Windows — install via winget
winget install Microsoft.DSC

# Verify the binary is in PATH
dsc --version

On Ubuntu or Debian, add the Microsoft package repository and install the dsc package:

# On the Linux machine (run as root or sudo)
curl -sSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /usr/share/keyrings/microsoft.gpg
echo "deb [signed-by=/usr/share/keyrings/microsoft.gpg] https://packages.microsoft.com/ubuntu/22.04/prod jammy main" \
    | tee /etc/apt/sources.list.d/microsoft.list
apt-get update && apt-get install -y dsc

Writing Your First DSC v3 Resource Configuration in JSON/YAML

A DSC v3 configuration document describes the desired state of one or more resources. The top-level keys are $schema, resources, and an optional variables block. Each resource entry names a registered resource type and supplies its required properties.

The following YAML document ensures a registry value exists and a local file is present with specific content:

# desired-state.yaml
$schema: https://schemas.microsoft.com/dsc/2023/08/config.schema.json
resources:
  - name: Set timezone registry value
    type: Microsoft.Windows/Registry
    properties:
      keyPath: HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
      valueName: TimeZoneKeyName
      valueData:
        String: UTC

  - name: Ensure audit policy file exists
    type: Microsoft.DSC/File
    properties:
      path: C:\Config\audit-policy.txt
      content: "CIS Benchmark L1 applied"
      ensure: Present

Apply the configuration with dsc config set:

dsc config set --path .\desired-state.yaml

Invoking dsc config with PowerShell Wrapper Functions

Because dsc is a CLI binary, PowerShell wraps it cleanly. You can capture structured JSON output, test drift without making changes, and integrate the results into larger orchestration pipelines. The three primary subcommands are get (read current state), test (compare to desired), and set (enforce desired state).

function Invoke-DscConfig {
    param(
        [Parameter(Mandatory)]
        [ValidateSet('get','test','set')]
        [string]$Command,

        [Parameter(Mandatory)]
        [string]$ConfigPath
    )

    $result = dsc config $Command --path $ConfigPath --output-format json 2>&1
    if ($LASTEXITCODE -ne 0) {
        throw "dsc config $Command failed with exit code $LASTEXITCODE: $result"
    }
    $result | ConvertFrom-Json
}

# Test for drift without making changes
$drift = Invoke-DscConfig -Command test -ConfigPath .\desired-state.yaml
$drift.results | Where-Object { -not $_.result.inDesiredState }

Available Built-In Resources: Registry, File, Package

DSC v3 ships with a small set of cross-platform and Windows-specific built-in resources. On Windows the most useful are Microsoft.Windows/Registry for managing registry keys and values, Microsoft.DSC/File for files and directories, and Microsoft.Windows/WindowsPackage for MSI and winget-based packages. Linux gains Microsoft.DSC/File and adapter resources that invoke existing PSDSC (v2) module resources for backward compatibility via the Microsoft.DSC/PowerShell adapter.

List all resources registered on the current system:

dsc resource list --output-format json | ConvertFrom-Json | Select-Object type, version

Building a Custom Class-Based Resource

Custom DSC v3 resources are executables that accept JSON on stdin and write JSON to stdout. You can write them in any language, including PowerShell 7. A PowerShell-based resource is packaged as a script that handles the get, test, and set operations based on a --operation argument. The resource manifest (a JSON file) tells dsc how to invoke it.

# MyCompany.NtpConfig/MyCompany.NtpConfig.ps1
param([string]$Operation)

$input = $null
if (-not [Console]::IsInputRedirected -eq $false) {
    $input = $Host.UI.RawUI.ReadLine() | ConvertFrom-Json
}

switch ($Operation) {
    'get' {
        $current = (w32tm /query /status) -join "`n"
        [PSCustomObject]@{ server = $current } | ConvertTo-Json
    }
    'test' {
        $desired = $input.server
        $current = ((w32tm /query /status) | Select-String 'Source').ToString()
        [PSCustomObject]@{ inDesiredState = $current -match [regex]::Escape($desired) } | ConvertTo-Json
    }
    'set' {
        w32tm /config /manualpeerlist:$($input.server) /syncfromflags:manual /reliable:YES /update | Out-Null
        $input | ConvertTo-Json
    }
}

Integration with Azure Machine Configuration

Azure Machine Configuration (formerly Azure Policy Guest Configuration) uses DSC v3 as its underlying engine for auditing and enforcing machine state on Azure VMs, Arc-enabled servers, and other managed machines. A DSC v3 configuration package is wrapped in a zip archive with a manifest and assigned to machines via Azure Policy. This means the exact same YAML or JSON configuration you test locally can be promoted to policy-enforced compliance at scale. The GuestConfiguration PowerShell module provides New-GuestConfigurationPackage to build the package and Publish-GuestConfigurationPackage to upload it to Azure Storage.

Common Errors

  • DSC v3 binary not in PATH after installation on Windows. The MSI installs dsc.exe to %ProgramFiles%\dsc but the installer does not always refresh the current session’s $env:PATH. Close and reopen the terminal, or add the path manually: $env:PATH += ";$env:ProgramFiles\dsc". Verify with Get-Command dsc.
  • Class-based resource test method returns wrong type causing infinite remediation loop. The test operation must return a JSON object with a boolean inDesiredState property. Returning a string like "True" instead of the boolean true causes DSC to treat the resource as always out of state. Ensure ConvertTo-Json serializes the value as a boolean, not a string — use [bool]$result rather than "$result".

Related Cmdlets / See Also

Wrapping Up

DSC v3 represents a genuine architectural step forward — cross-platform, LCM-free, and language-agnostic at the resource layer. Start by installing the binary, test drift with dsc config test before applying any changes, and build custom resources as plain executables. Once your configurations are solid locally, Azure Machine Configuration gives you a direct path from script to enforced policy.

Send-Item -To