450 lines
11 KiB
Markdown
450 lines
11 KiB
Markdown
# Winget Configure vs DSC CLI: In-Depth Comparison
|
|
|
|
Both `winget configure` and the `dsc` CLI can apply declarative configurations that include winget packages. This doc explains when to use each, their differences, and practical examples.
|
|
|
|
---
|
|
|
|
## Quick Comparison
|
|
|
|
| Aspect | `winget configure` | `dsc` CLI |
|
|
|--------|-------------------|-----------|
|
|
| **Focus** | Winget-centric configurations | General-purpose DSC (any resource) |
|
|
| **Output** | Human-friendly, interactive | JSON output, scriptable |
|
|
| **State checking** | Limited | Full (`get`, `test`, `set`) |
|
|
| **Diffing** | No built-in | Yes (`dsc config test`) |
|
|
| **Complexity** | Simpler | More powerful |
|
|
| **Install** | Built into winget | Separate install (`winget install Microsoft.DSC`) |
|
|
|
|
---
|
|
|
|
## Entry Points
|
|
|
|
### Winget Configure
|
|
|
|
```powershell
|
|
# Apply a configuration
|
|
winget configure ./config.dsc.yaml
|
|
|
|
# Apply with auto-accept (for scripts)
|
|
winget configure ./config.dsc.yaml --accept-configuration-agreements
|
|
|
|
# Show what would happen (dry run) — limited support
|
|
winget configure show ./config.dsc.yaml
|
|
```
|
|
|
|
### DSC CLI
|
|
|
|
```powershell
|
|
# Check current state (what IS installed)
|
|
dsc config get --file ./config.dsc.yaml
|
|
|
|
# Test if current state matches desired (diffing)
|
|
dsc config test --file ./config.dsc.yaml
|
|
|
|
# Apply the configuration
|
|
dsc config set --file ./config.dsc.yaml
|
|
|
|
# Export current state to a config
|
|
dsc config export --resource Microsoft.WinGet.DSC/WinGetPackage
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration File Format
|
|
|
|
Both use the same YAML format (DSCv3 schema):
|
|
|
|
```yaml
|
|
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
|
|
properties:
|
|
configurationVersion: 0.2.0
|
|
resources:
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
id: install-vscode
|
|
directives:
|
|
description: Install VS Code
|
|
allowPrerelease: true
|
|
settings:
|
|
id: Microsoft.VisualStudioCode
|
|
source: winget
|
|
```
|
|
|
|
---
|
|
|
|
## Example Project Structures
|
|
|
|
### Option A: Winget Configure (Simple Setup)
|
|
|
|
Best for: Personal machine setup, quick provisioning
|
|
|
|
```
|
|
my-windows-config/
|
|
├── config.dsc.yaml # Main configuration
|
|
├── README.md
|
|
└── install.ps1 # Optional wrapper script
|
|
```
|
|
|
|
**config.dsc.yaml**
|
|
```yaml
|
|
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
|
|
properties:
|
|
configurationVersion: 0.2.0
|
|
resources:
|
|
# Developer Tools
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
directives:
|
|
description: Visual Studio Code
|
|
settings:
|
|
id: Microsoft.VisualStudioCode
|
|
source: winget
|
|
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
directives:
|
|
description: Git
|
|
settings:
|
|
id: Git.Git
|
|
source: winget
|
|
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
directives:
|
|
description: Node.js LTS
|
|
settings:
|
|
id: OpenJS.NodeJS.LTS
|
|
source: winget
|
|
version: "20.10.0" # Pinned version
|
|
```
|
|
|
|
**install.ps1**
|
|
```powershell
|
|
#!/usr/bin/env pwsh
|
|
Write-Host "Applying Windows configuration..." -ForegroundColor Cyan
|
|
winget configure ./config.dsc.yaml --accept-configuration-agreements
|
|
Write-Host "Done!" -ForegroundColor Green
|
|
```
|
|
|
|
**Usage:**
|
|
```powershell
|
|
.\install.ps1
|
|
# or directly:
|
|
winget configure ./config.dsc.yaml
|
|
```
|
|
|
|
---
|
|
|
|
### Option B: DSC CLI (Advanced/Enterprise)
|
|
|
|
Best for: CI/CD, drift detection, mixed resource types, automation
|
|
|
|
```
|
|
my-windows-config/
|
|
├── configs/
|
|
│ ├── packages.dsc.yaml # Winget packages
|
|
│ ├── settings.dsc.yaml # Windows settings/registry
|
|
│ └── full.dsc.yaml # Combined config
|
|
├── scripts/
|
|
│ ├── apply.ps1
|
|
│ ├── test.ps1 # Drift detection
|
|
│ └── export.ps1 # Generate config from current state
|
|
├── lockfiles/
|
|
│ └── packages.lock.yaml # Version-locked config
|
|
└── README.md
|
|
```
|
|
|
|
**configs/packages.dsc.yaml**
|
|
```yaml
|
|
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
|
|
properties:
|
|
configurationVersion: 0.2.0
|
|
resources:
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
id: vscode
|
|
directives:
|
|
description: Visual Studio Code
|
|
settings:
|
|
id: Microsoft.VisualStudioCode
|
|
source: winget
|
|
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
id: git
|
|
directives:
|
|
description: Git
|
|
settings:
|
|
id: Git.Git
|
|
source: winget
|
|
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
id: nodejs
|
|
directives:
|
|
description: Node.js LTS
|
|
settings:
|
|
id: OpenJS.NodeJS.LTS
|
|
source: winget
|
|
```
|
|
|
|
**scripts/apply.ps1**
|
|
```powershell
|
|
#!/usr/bin/env pwsh
|
|
param(
|
|
[string]$Config = "./configs/packages.dsc.yaml"
|
|
)
|
|
|
|
Write-Host "Testing current state..." -ForegroundColor Cyan
|
|
$testResult = dsc config test --file $Config | ConvertFrom-Json
|
|
|
|
if ($testResult.results | Where-Object { $_.result.inDesiredState -eq $false }) {
|
|
Write-Host "Drift detected. Applying configuration..." -ForegroundColor Yellow
|
|
dsc config set --file $Config
|
|
} else {
|
|
Write-Host "System is already in desired state." -ForegroundColor Green
|
|
}
|
|
```
|
|
|
|
**scripts/test.ps1** (Drift Detection)
|
|
```powershell
|
|
#!/usr/bin/env pwsh
|
|
param(
|
|
[string]$Config = "./configs/packages.dsc.yaml"
|
|
)
|
|
|
|
Write-Host "Checking for configuration drift..." -ForegroundColor Cyan
|
|
|
|
$result = dsc config test --file $Config | ConvertFrom-Json
|
|
|
|
$drifted = $result.results | Where-Object { $_.result.inDesiredState -eq $false }
|
|
|
|
if ($drifted) {
|
|
Write-Host "`nDrift detected in:" -ForegroundColor Red
|
|
$drifted | ForEach-Object {
|
|
Write-Host " - $($_.resource.type): $($_.resource.id)" -ForegroundColor Yellow
|
|
}
|
|
exit 1
|
|
} else {
|
|
Write-Host "No drift detected. System matches desired state." -ForegroundColor Green
|
|
exit 0
|
|
}
|
|
```
|
|
|
|
**scripts/export.ps1** (Generate Config from Current State)
|
|
```powershell
|
|
#!/usr/bin/env pwsh
|
|
# Export currently installed winget packages to a DSC config
|
|
|
|
$packages = winget list --source winget | Select-Object -Skip 2 | ForEach-Object {
|
|
$parts = $_ -split '\s{2,}'
|
|
if ($parts.Length -ge 2) {
|
|
@{
|
|
name = $parts[0]
|
|
id = $parts[1]
|
|
version = if ($parts.Length -ge 3) { $parts[2] } else { $null }
|
|
}
|
|
}
|
|
} | Where-Object { $_ -ne $null }
|
|
|
|
# Output as DSC YAML format
|
|
Write-Output "# Auto-generated from current system state"
|
|
Write-Output "# yaml-language-server: `$schema=https://aka.ms/configuration-dsc-schema/0.2"
|
|
Write-Output "properties:"
|
|
Write-Output " configurationVersion: 0.2.0"
|
|
Write-Output " resources:"
|
|
|
|
foreach ($pkg in $packages) {
|
|
Write-Output " - resource: Microsoft.WinGet.DSC/WinGetPackage"
|
|
Write-Output " id: $($pkg.id.ToLower() -replace '[^a-z0-9]', '-')"
|
|
Write-Output " settings:"
|
|
Write-Output " id: $($pkg.id)"
|
|
Write-Output " source: winget"
|
|
if ($pkg.version) {
|
|
Write-Output " version: `"$($pkg.version)`""
|
|
}
|
|
Write-Output ""
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Version Locking
|
|
|
|
### With Winget Configure
|
|
|
|
Pin versions directly in the YAML:
|
|
|
|
```yaml
|
|
resources:
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
settings:
|
|
id: OpenJS.NodeJS.LTS
|
|
source: winget
|
|
version: "20.10.0" # Exact version lock
|
|
```
|
|
|
|
### With DSC CLI
|
|
|
|
Same approach, but you can also generate a locked config:
|
|
|
|
```powershell
|
|
# Get current installed versions
|
|
dsc config get --file ./config.dsc.yaml > current-state.json
|
|
|
|
# Or use winget export with versions
|
|
winget export -o winget-lock.json --include-versions
|
|
```
|
|
|
|
**Lockfile Pattern:**
|
|
|
|
Create two files:
|
|
- `packages.dsc.yaml` — Desired packages (may float versions)
|
|
- `packages.lock.dsc.yaml` — Locked versions for reproducibility
|
|
|
|
```yaml
|
|
# packages.lock.dsc.yaml - Generated/maintained with exact versions
|
|
properties:
|
|
configurationVersion: 0.2.0
|
|
resources:
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
id: nodejs
|
|
settings:
|
|
id: OpenJS.NodeJS.LTS
|
|
source: winget
|
|
version: "20.10.0"
|
|
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
id: git
|
|
settings:
|
|
id: Git.Git
|
|
source: winget
|
|
version: "2.43.0"
|
|
```
|
|
|
|
---
|
|
|
|
## Diffing / Drift Detection
|
|
|
|
### Winget Configure
|
|
|
|
Limited support — `winget configure show` gives some info but no true diff:
|
|
|
|
```powershell
|
|
winget configure show ./config.dsc.yaml
|
|
```
|
|
|
|
### DSC CLI (Full Diffing)
|
|
|
|
```powershell
|
|
# Test returns JSON with inDesiredState boolean for each resource
|
|
dsc config test --file ./config.dsc.yaml
|
|
```
|
|
|
|
**Example output:**
|
|
```json
|
|
{
|
|
"results": [
|
|
{
|
|
"resource": {
|
|
"type": "Microsoft.WinGet.DSC/WinGetPackage",
|
|
"id": "vscode"
|
|
},
|
|
"result": {
|
|
"inDesiredState": true
|
|
}
|
|
},
|
|
{
|
|
"resource": {
|
|
"type": "Microsoft.WinGet.DSC/WinGetPackage",
|
|
"id": "nodejs"
|
|
},
|
|
"result": {
|
|
"inDesiredState": false,
|
|
"diff": {
|
|
"version": {
|
|
"desired": "20.10.0",
|
|
"actual": "18.19.0"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**CI/CD Integration:**
|
|
```powershell
|
|
# In a CI pipeline - fail if drift detected
|
|
$result = dsc config test --file ./config.dsc.yaml | ConvertFrom-Json
|
|
$hasDrift = $result.results | Where-Object { -not $_.result.inDesiredState }
|
|
|
|
if ($hasDrift) {
|
|
Write-Error "Configuration drift detected!"
|
|
exit 1
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## When to Use Which
|
|
|
|
### Use `winget configure` when:
|
|
|
|
- ✅ You want a simple, interactive setup experience
|
|
- ✅ Your config is mostly/entirely winget packages
|
|
- ✅ You're doing one-time machine provisioning
|
|
- ✅ You don't need drift detection
|
|
- ✅ You want minimal dependencies (built into winget)
|
|
|
|
### Use `dsc` CLI when:
|
|
|
|
- ✅ You need drift detection / compliance checking
|
|
- ✅ You're building CI/CD pipelines
|
|
- ✅ You want JSON output for automation
|
|
- ✅ You're mixing winget with other DSC resources (registry, files, etc.)
|
|
- ✅ You need the full `get`/`test`/`set` lifecycle
|
|
- ✅ Enterprise configuration management
|
|
|
|
---
|
|
|
|
## Mixed Resource Example (DSC Only)
|
|
|
|
DSC can combine winget packages with other configuration types:
|
|
|
|
```yaml
|
|
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
|
|
properties:
|
|
configurationVersion: 0.2.0
|
|
resources:
|
|
# Install VS Code
|
|
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
|
id: vscode
|
|
settings:
|
|
id: Microsoft.VisualStudioCode
|
|
source: winget
|
|
|
|
# Configure VS Code settings (after install)
|
|
- resource: Microsoft.Windows.Developer/DeveloperMode
|
|
id: enable-dev-mode
|
|
settings:
|
|
Ensure: Present
|
|
|
|
# Set environment variable
|
|
- resource: Microsoft.Windows.Developer/EnvironmentVariable
|
|
id: set-editor
|
|
settings:
|
|
Name: EDITOR
|
|
Value: code
|
|
Target: User
|
|
```
|
|
|
|
This is where DSC really shines — you can configure the entire system state, not just packages.
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
| Task | Winget Configure | DSC CLI |
|
|
|------|-----------------|---------|
|
|
| Apply config | `winget configure ./config.yaml` | `dsc config set --file ./config.yaml` |
|
|
| Check current state | ❌ | `dsc config get --file ./config.yaml` |
|
|
| Diff/test | Limited | `dsc config test --file ./config.yaml` |
|
|
| Output format | Human text | JSON (scriptable) |
|
|
| Version locking | Manual in YAML | Manual in YAML + export tools |
|
|
| Multiple resource types | Winget only | Any DSC resource |
|
|
|