Working with parameters in Microsoft Desired State Configuration (DSC)
Learn how to leverage parameters in Microsoft DSC configuration documents
        If you worked with PowerShell Desired State Configuration (PSDSC), you know the pain.
Managing parameters was a nightmare. You wrote a configuration. You compiled it into an MOF file. You deployed that MOF. Then you needed different parameters for staging. So you compiled again. Then production needed different values. You compiled a third time.
Every parameter change meant recompiling. Every environment needed its own MOF file. Every deployment required managing and distributing these files across your infrastructure.
It was exhausting.
Microsoft Desired State Configuration (DSC) changes everything.
Parameters are processed at runtime. One configuration file. Multiple environments. No compilation. No MOF files. No distribution headache.
You define your configuration once. You run it with different parameters. That's it.
This article shows you how, starting with a comparison of PSDSC versus Microsoft DSC.
Comparing parameters
Before you look at how you can work with parameters in Microsoft DSC, let's see both scenarios in both systems using a real-world example: deploying a web server configuration to production with environment-specific parameters.
In a compilation workflow using PSDSC, the following configuration document illustrates what happens:
# Step 1: Define the configuration script
Configuration WebServerConfig {
    param(
        [string]$Environment = 'Development',
        [int]$Port = 8080
    )
    Import-DscResource -ModuleName PSDesiredStateConfiguration
    
    Node $ServerName {
        WindowsFeature IIS {
            Name = 'Web-Server'
            Ensure = 'Present'
        }
        
        File ConfigFile {
            DestinationPath = "C:\Config\app.config"
            Contents = "Environment: $Environment`nPort: $Port"
        }
    }
}
# Step 2: COMPILE to MOF file (parameters become hardcoded)
WebServerConfig -Environment 'Production' -Port 443 -ServerName 'WebServer01' -OutputPath 'C:\MOFs'
# Creates: C:\MOFs\WebServer01.mof with hardcoded values
# Step 3: APPLY the MOF file (separate operation)
Start-DscConfiguration -Path 'C:\MOFs' -Wait
# Problem: To use different parameters, you must:
# 1. Recompile the configuration script
# 2. Generate a new MOF file
# 3. Distribute the new MOF to target systemsAs you can see, the challenge is clear: parameters are "baked into" the MOF file at compile time. Each environment needs its own MOF file. Changing values requires recompiling and redistributing.
Now let's look at how Microsoft DSC does it:
# webserver-config.dsc.yaml - One configuration for all environments
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
  environment:
    type: string
  port:
    type: int
  configPath:
    type: string
resources:
  - name: IIS Web Server
    type: Microsoft.Windows/WindowsPowerShell
    properties:
      resources:
        - name: Web-Server Feature
          type: PsDesiredStateConfiguration/WindowsFeature
          properties:
            Name: Web-Server
            Ensure: Present
        - name: Application Config File
          type: PsDesiredStateConfiguration/File
          properties:
            DestinationPath: "[parameters('configPath')]"
            Contents: "[concat('Environment: ', parameters('environment'), '\nPort: ', string(parameters('port')))]"
            Ensure: PresentTo run it for different environments, you can simply add the --parameters option when calling dsc at runtime:
# Development
dsc config get --file webserver-config.dsc.yaml --parameters '{"parameters":{"environment":"development","port":8080,"configPath":"C:\\Config\\dev-app.config"}}'
# Production
dsc config get --file webserver-config.dsc.yaml --parameters '{"parameters":{"environment":"production","port":443,"configPath":"C:\\Config\\prod-app.config"}}'
# Change values instantly - just provide different parameters
dsc config get --file webserver-config.dsc.yaml --parameters '{"parameters":{"environment":"staging","port":9000,"configPath":"C:\\Config\\staging-app.config"}}'The improvement is clear. Parameters are evaluated at runtime. One configuration file works everywhere, and the values can change instantly without any recompilation.
Here's a quick table of the key differences between PSDSC and Microsoft DSC:
| Aspect | PowerShell DSC | Microsoft DSC | 
|---|---|---|
| Parameter processing | Compile-time (static) | Runtime (dynamic) | 
| Workflow | Write script → Compile to MOF → Apply MOF | Write config → Execute with parameters | 
| Intermediate files | MOF files required | No MOF files | 
| Change parameters | Recompile + redistribute | Provide different values | 
| Multi-environment | One MOF per environment | One config + parameter files | 
| Parameter format | PowerShell function parameters | JSON/YAML files or inline | 
Understanding parameter definitions
Now that you see how Microsoft DSC differs from PSDSC, let’s look at the ways to pass parameters to your configurations, beginning with parameter definitions.
As you've seen in the above code snippet, parameters are defined with the parameters keyword. Take a look at the following configuration document:
# example-config.dsc.yaml
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
  environment:
    type: string
    defaultValue: development
    allowedValues:
      - development
      - staging
      - production
  port:
    type: int
    defaultValue: 8080
    minValue: 1
    maxValue: 65535
  serverName:
    type: string
    defaultValue: myserver
    minLength: 3
    maxLength: 15
  enableSSL:
    type: bool
    defaultValue: false
  tags:
    type: array
    defaultValue:
      - web
      - production
    minLength: 1
    maxLength: 5
resources:
  - name: Echo Configuration
    type: Microsoft.DSC.Debug/Echo
    properties:
      output: "[concat('Env: ', parameters('environment'), ', Server: ', parameters('serverName'), ', Port: ', string(parameters('port')), ', SSL: ', string(parameters('enableSSL')))]"Each parameter can have two properties:
- type: The data type (string, int, bool, array, object, secureString, secureObject).
 - defaultValue: Used if no value is provided.
 
It's also possible to add optional constraints:
- For string types: 
minLength,maxLength,allowedValues. - For int types: 
minValue,maxValue,allowedValues. - For array types: 
minLength,maxLength,allowedValues. - For all types: 
allowedValues(array of permitted values). 
Now that you know about the parameter definitions, let's look at how you can provide parameters to the engine.
Method 1: Using parameter files
Parameter files provide a structured way to define parameter values separately from your configuration. This is the most common and recommended approach for managing parameters.
For illustration purposes, you can create it in multiple ways. Choose the one that appeals to you.
Use JSON parameter file
Create the following JSON file containing your parameters:
// parameters.json
{
  "parameters": {
    "environment": "production",
    "port": 443,
    "serverName": "web-prod-01"
  }
}To use the parameter file, use it with your configuration:
dsc config --parameters-file parameters.json get --file example-config.dsc.yamlUse PowerShell to create a parameters file
You can create the parameters file using PowerShell and save it as JSON:
# Create parameters as a hashtable and convert to JSON
$params = @{
    parameters = @{
        environment = 'production'
        port = 443
        serverName = 'web-prod-01'
    }
} | ConvertTo-Json
# Save to file
$params | Set-Content -Path 'parameters.json'
# Use with DSC
dsc config --parameters-file parameters.json get --file example-config.dsc.yamlUse YAML parameter file
DSC also supports YAML parameter files, which can be more readable for complex structures:
# parameters.yaml
parameters:
  environment: production
  port: 443
  serverName: web-prod-01
  tags:
    - web
    - critical
  metadata:
    owner: platform-team
    costCenter: engineeringThen, to apply the parameter file, you'll run:
dsc config --parameters-file parameters.yaml get --file example-config.dsc.yamlBonus: Using YaYaml in PowerShell
If you prefer to stick with PowerShell and convert parameter files from a hashtable, use the YaYaml PowerShell module:
# Install YaYaml module if not already installed
Install-PSResource -Name YaYaml -Scope CurrentUser
# Create parameters as a hashtable
$params = @{
    parameters = @{
        environment = 'production'
        port = 443
        serverName = 'web-prod-01'
        tags = @('web', 'critical')
        metadata = @{
            owner = 'platform-team'
            costCenter = 'engineering'
        }
    }
}
# Convert to YAML and save
$params | ConvertTo-Yaml -Depth 10 | Set-Content -Path 'parameters.yaml'
# Use with DSC
dsc config --parameters-file parameters.yaml get --file example-config.dsc.yamlMethod 2: Using inline parameters
This example was showcased in the introduction. Inline parameters allow you to pass parameters directly on the command line without creating a separate file. This is useful for quick testing.
To pass parameters as a JSON string, you can use the --parameters or -p flag:
dsc config --parameters '{"parameters":{"environment":"staging"}}' get --file example-config.dsc.yamlIf you want to fallback on PowerShell to construct the proper JSON, use:
# Create parameters as hashtable and convert to JSON
$inlineParams = @{
    parameters = @{
        environment = 'staging'
        port = 9000
    }
} | ConvertTo-Json -Compress
# Pass to DSC
dsc config --parameters $inlineParams get --file example-config.dsc.yamlAs a bonus, you can also pass in YAML with the YaYaml PowerShell module:
# Convert parameters to YAML and pass inline
$inlineParams = @{
    parameters = @{
        environment = 'staging'
        port = 9000
        tags = @('web', 'staging')
    }
} | ConvertTo-Yaml
# Pass YAML string to DSC
dsc config --parameters $inlineParams get --file example-config.dsc.yamlMethod 3: Using STDIN with pipeline
DSC allows you to read parameter files from standard input (STDIN). This provides for pipeline scenarios and integration with other tools.
To read from STDIN, you can use the - as the parameter file path:
cat parameters.json | dsc config --parameters-file - get --file example-config.dsc.yamlIf you want to construct it using PowerShell, use:
$params = @{
    parameters = @{
        environment = 'production'
        port = 443
    }
} | ConvertTo-Json
$params | Set-Content -Path parameters.json
Get-Content 'parameters.json' | dsc config --parameters-file - get --file example-config.dsc.yamlThe same would imply for YAML:
# Convert parameters to YAML and pipe to DSC
$params = @{
    parameters = @{
        environment = 'production'
        port = 443
        tags = @('web', 'production')
    }
} | ConvertTo-Yaml
$params | Set-Content -Path 'parameters.yaml'
# Pipe YAML file to DSC
Get-Content 'parameters.yaml' | dsc config --parameters-file - get --file example-config.dsc.yamlMethod 4: Merging multiple parameter sources
DSC allows you to merge parameters from multiple sources, with inline parameters taking precedence over parameter files. This enables you to dynamically pass in parameters for complex deployments.
To combine a parameter file with inline overrides, use PowerShell:
# Base parameters in file
$baseParams = @{
    parameters = @{
        environment = 'production'
        port = 443
        enableSSL = $true
        logLevel = 'info'
    }
} | ConvertTo-Json
$baseParams | Set-Content -Path 'base-parameters.json'
# Override specific parameters inline
$overrideParams = @{
    parameters = @{
        port = 8443
        logLevel = 'debug'
    }
} | ConvertTo-Json -Compress
# Merged result: environment=production, port=8443, enableSSL=true, logLevel=debug
dsc config --parameters-file base-parameters.json --parameters $overrideParams get --file example-config.dsc.yamlWhen merging parameters from multiple sources, DSC will apply the following precedence:
- Inline parameters
 - Parameter file
 - Default values
 
Best practices
You've learned the mechanics of passing parameters to DSC configurations. Now let's talk about doing it right.
These aren't theoretical guidelines. They're lessons learned from the field and real deployments. Follow them, and you'll avoid the common pitfalls that make parameter management painful.
Use parameter files for environment configuration
Store environment-specific configurations in a separate folder in version control:
parameters/
├── development.json
├── staging.json
└── production.json
Or:
parameters/
├── development.yaml
├── staging.yaml
└── production.yamlLeverage default values
Provide sensible defaults for parameters that rarely change:
parameters:
  logLevel:
    type: string
    defaultValue: info  # Reasonable default
  port:
    type: int
    defaultValue: 8080  # Common default
  environment:
    type: string
    # No default - must be explicitly providedValidate with constraints
Use constraints to prevent invalid configurations:
parameters:
  environment:
    type: string
    allowedValues:
      - development
      - staging
      - production
  
  port:
    type: int
    minValue: 1
    maxValue: 65535
  
  serverName:
    type: string
    minLength: 3
    maxLength: 15Document your parameters
Each parameter declared in your configuration document can be documented using the metadata keyword:
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
  environment:
    type: string
    defaultValue: development
    allowedValues:
      - development
      - staging
      - production
    metadata: 
      description: Deployment environment
  port:
    type: int
    defaultValue: 8080
    minValue: 1
    maxValue: 65535
    metadata:
      description: TCP port number for the application
  serverName:
    type: string
    defaultValue: myserver
    minLength: 3
    maxLength: 15
    metadata:
      description: Server hostname or identifier
  enableSSL:
    type: bool
    defaultValue: false
    metadata:
      description: Enable SSL/TLS encryption
  tags:
    type: array
    defaultValue:
      - web
      - production
    minLength: 1
    maxLength: 5
    metadata:
      description: Resource tags for categorization
# truncatedSummary
Microsoft DSC provides flexible methods for passing parameters to configurations. You've learned four methods:
- Parameter files: Best for environment configurations.
 - Inline parameters: Ideal for quick tests.
 - STDIN: Enables pipeline input and integration scenarios.
 - Parameter merging: Combines multiple sources with clear precedence (unofficial).
 
Choose the method that best fits your use case, or combine methods for flexibility. The declarative nature of Microsoft DSC configurations, combined with its parameter system, enables reusable configuration management across multiple platforms.