Files
winos-config/docs/winget-configure-vs-dsc.md
EthanShoeDev 01a35296a9 init
2025-11-30 17:52:15 -05:00

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 |