Skill v1.0.0
Trusted Publisher100/100version: "1.0.0"
name: dsc-resource-authoring description: > Helps discover DSC resources available via dsc.exe, author new configuration.winget files for this repository, and debug existing DSC configurations. Use this skill when the user asks to add a new flow, pick a DSC resource, write or fix a configuration.winget, or debug a winget configure error.
DSC Resource Authoring Skill
This skill guides you through three related tasks that all revolve around
dsc.exe (DSC v3) and winget configure:
- Discover — enumerate and inspect resources available on the machine.
- Author — compose a valid
configuration.wingetfile that follows
the rules in AGENTS.md.
- Debug — validate and diagnose an existing configuration.
Read AGENTS.md at the repo root before starting. It is the authoritative
source of rules; this skill translates those rules into concrete dsc commands.
Phase 1 — Discover Available Resources
List all resources
dsc resource list -o json | ConvertFrom-Json
Using -o json gives structured output that is easy to filter and inspect.
Key fields on each object:
- type — the resource type string you put in the
type:field of a.winget. - kind —
Resource,Adapter, orGroup. - version — the resource module version.
Filter by name or adapter
# Find WinGet-related resourcesdsc resource list -o json | ConvertFrom-Json | Where-Object { $_.type -like '*WinGet*' }# Extract just the type strings for quick scanningdsc resource list -o json | ConvertFrom-Json | Select-Object -ExpandProperty type | Sort-Object
For a new language/tool flow the two relevant types are:
- `Microsoft.WinGet/Package` — dscv3 native resource (preferred, see AGENTS.md §3).
- `Microsoft.WinGet.DSC/WinGetPackage` — v0.2 PowerShell resource (fallback
only when PSDscResources/Script is also needed).
Inspect a resource's schema
dsc resource schema --resource Microsoft.WinGet/Package -o json | ConvertFrom-Json
This emits the JSON Schema for the resource as a structured object. Drill into
specific properties to confirm names and types — e.g. confirm that
acceptAgreements (required by AGENTS.md §4) is present:
$schema = dsc resource schema --resource Microsoft.WinGet/Package -o json | ConvertFrom-Json$schema.properties.PSObject.Properties | Select-Object Name
Find the exact winget package id
# Search the winget community repowinget search <keyword># Confirm the id exists and check available versionswinget show <Publisher.Product>
Per AGENTS.md §6, always use a versioned id (e.g. Python.Python.3.14),
never a bare id (e.g. Python.Python).
Phase 2 — Author a configuration.winget
Ask the user what they want to install
Use ask_user to confirm:
- The package(s) to install and the preferred minor version.
- Whether a post-install PowerShell step is needed (if yes → v0.2 with
PSDscResources/Script; otherwise → dscv3, which is strongly preferred).
- Whether there are install-order dependencies between packages.
Choose the schema version (AGENTS.md §3)
| Need | Schema | Resource | |
|---|---|---|---|
| Pure package install | dscv3 | Microsoft.WinGet/Package | |
| Simple fire-and-forget command | dscv3 | Microsoft.DSC.Transitional/RunCommandOnSet | |
| Idempotent PowerShell 7 script (get/test/set) | dscv3 | Microsoft.DSC.Transitional/PowerShellScript | |
| Idempotent Windows PowerShell 5.1 script (get/test/set) | dscv3 | Microsoft.DSC.Transitional/WindowsPowerShellScript | |
Requires PSDscResources/Script specifically | v0.2 | Microsoft.WinGet.DSC/WinGetPackage + PSDscResources/Script |
Prefer the native dscv3 Microsoft.DSC.Transitional/* resources over v0.2 + PSDscResources/Script
whenever possible — they keep the dscv3 document shape and do not require dropping the schema version.
Only fall back to v0.2 if the CI runner cannot resolve the Transitional resources.
dscv3 template (preferred)
# yaml-language-server: $schema=https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json## Canonical invocation:# winget configure --file configuration.winget --disable-interactivity --accept-configuration-agreements## Package id tracks <Publisher.Product> minor release line.# Bump the id when the current minor goes EOL or the manifest 404s.$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.jsonmetadata:winget:processor: dscv3resources:- name: <PascalName>type: Microsoft.WinGet/Packagemetadata:securityContext: elevatedproperties:id: <Publisher.Product.MajorMinor>source: wingetacceptAgreements: true
dscv3 — RunCommandOnSet (fire-and-forget, runs only on Set)
Use when you need to run a single command or script file as a post-step and
idempotency checking is handled externally (or not required). The resource only
runs its command during a set operation; get and test are no-ops.
- name: RunMySetupCommandtype: Microsoft.DSC.Transitional/RunCommandOnSetproperties:executable: pwsharguments:- -NoProfile- -NoLogo- -File- C:\setup\configure-something.ps1
To run an inline snippet instead of a script file, use -Command:
- name: InstallPSModuletype: Microsoft.DSC.Transitional/RunCommandOnSetproperties:executable: pwsharguments:- -NoProfile- -NoLogo- -Command- if (-not (Get-Module -ListAvailable MyModule)) { Install-Module MyModule -Force }
dscv3 — PowerShellScript (idempotent, PowerShell 7)
Use when you need full get/test/set idempotency in PowerShell 7. DSC calls
testScript first; if it returns $true, setScript is skipped.
_inDesiredState: true in the output signals "no change needed".
- name: ConfigureMyTooltype: Microsoft.DSC.Transitional/PowerShellScriptproperties:getScript: |$configured = Test-Path "$env:APPDATA\MyTool\config.json"return @{ configured = $configured }testScript: |return Test-Path "$env:APPDATA\MyTool\config.json"setScript: |New-Item -ItemType Directory -Force "$env:APPDATA\MyTool" | Out-Null'{"theme":"dark"}' | Set-Content "$env:APPDATA\MyTool\config.json"
dscv3 — WindowsPowerShellScript (idempotent, Windows PowerShell 5.1)
Identical schema to PowerShellScript but runs in powershell.exe (5.1).
Use when the script relies on a module or API only available in Windows PowerShell.
- name: ConfigureWithPS51type: Microsoft.DSC.Transitional/WindowsPowerShellScriptproperties:getScript: |return @{ Result = (Get-ItemPropertyValue HKCU:\Software\MyApp -Name Setting -EA SilentlyContinue) }testScript: |$val = Get-ItemPropertyValue HKCU:\Software\MyApp -Name Setting -EA SilentlyContinuereturn $val -eq 1setScript: |New-Item -Path HKCU:\Software\MyApp -Force | Out-NullSet-ItemProperty -Path HKCU:\Software\MyApp -Name Setting -Value 1
Key rules to enforce (AGENTS.md §4, §6, §12):
acceptAgreements: truemust appear on everyMicrosoft.WinGet/Package
resource. Do not rely on CLI-level flags for consent.
$schemaURL must be
https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
(not an aka.ms short link).
- Package id must be versioned to minor level.
v0.2 template (only when PSDscResources/Script is needed)
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2## Canonical invocation (agreement flags required because v0.2 lacks acceptAgreements property):# winget configure --file configuration.winget --disable-interactivity \# --accept-configuration-agreements --accept-package-agreementsproperties:configurationVersion: 0.2.0resources:- resource: Microsoft.WinGet.DSC/WinGetPackageid: Install<PascalName>directives:description: Install <Name>allowPrerelease: falsesettings:id: <Publisher.Product.MajorMinor>source: winget- resource: PSDscResources/Scriptid: Configure<PascalName>dependsOn: [Install<PascalName>]settings:GetScript: |return @{ Result = '' }TestScript: |# return $true if already in desired stateSetScript: |# bring the system into desired state
Write the file
Place it at scripts/windows/<id>/configuration.winget. After writing, verify
it parses cleanly:
python3 -c "import yaml; yaml.safe_load(open('scripts/windows/<id>/configuration.winget'))"
Phase 3 — Debug an Existing Configuration
Validate YAML syntax
python3 -c "import yaml; yaml.safe_load(open('<path-to-config>'))"
Dry-run the configuration
# Test what-if (does not apply changes); JSON makes pass/fail easy to inspectdsc config test --file <path-to-config> -o json | ConvertFrom-Json
Check resource get state
# Read the current state of a specific resourcedsc resource get --resource Microsoft.WinGet/Package -o json `--input '{"id":"<Publisher.Product.MajorMinor>"}' | ConvertFrom-Json
Apply with verbose output
winget configure --file <path-to-config> --disable-interactivity --accept-configuration-agreements --verbose-logs
Logs are written to %LOCALAPPDATA%\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir\.
Common failure patterns
| Symptom | Likely cause | Fix | |
|---|---|---|---|
acceptAgreements missing/false | Consent not passed | Add acceptAgreements: true to every Microsoft.WinGet/Package resource | |
| Package id not found | Unversioned or wrong id | Run winget search to confirm the exact id; use minor-versioned form | |
$schema URL rejected | Wrong schema URL | Use raw.githubusercontent.com/PowerShell/DSC/... URL, not aka.ms | |
| Interactive prompt during CI | --disable-interactivity missing | apply-configuration.ps1 adds this; verify it is invoked via the shim | |
PSDscResources/Script fails on dscv3 | Wrong schema version | Switch to v0.2 for any config that needs Script resources |
Checklist Before Committing a New Flow
Run the static checks from AGENTS.md §11:
# 1. YAML parsespython3 -c "import yaml; yaml.safe_load(open('scripts/windows/<id>/configuration.winget'))"# 2. manifest.yml is validpython3 - <<'PY'import yamldoc = yaml.safe_load(open("manifest.yml"))for flow in doc["flows"]:for os_name in flow["os"]:spec = flow.get(os_name) or {}missing = [k for k in ("install", "run", "expected") if not spec.get(k)]assert not missing, f"{flow['id']}/{os_name} missing {missing}"print("OK:", flow["id"], os_name)PY# 3. All .ps1 files parseGet-ChildItem -Recurse -Filter *.ps1 | ForEach-Object {$errs = $null[void][System.Management.Automation.Language.Parser]::ParseFile($_.FullName, [ref]$null, [ref]$errs)if ($errs) { Write-Error "$($_.FullName): $errs" } else { "OK: $($_.Name)" }}