A composable, declarative Windows configuration system.
Managing Windows configuration has traditionally been fragmented across multiple tools, scripts, and manual processes. Users often find themselves:
- Juggling multiple tools: PowerShell scripts, registry editors, package managers, and various utilities scattered across different contexts
- Lacking reproducibility: Manual configuration changes are hard to track, reproduce, or share across machines
- No clear separation of concerns: Mixing idempotent state management with one-time actions leads to unpredictable results
- External dependencies: Configuration tools often require YAML parsers, JSON schemas, or other non-native dependencies
WinSpec solves these problems by providing:
- Unified architecture: All Windows configuration in one cohesive system
- PowerShell-native configuration: No YAML, no JSON - just native PowerShell hashtables
- Clear provider taxonomy: Declarative (idempotent) vs Trigger (one-time) actions are explicitly separated
- Composable specifications: Import and merge configurations for modular, reusable setups
- Zero external dependencies: Pure PowerShell implementation works out of the box
WinSpec (Windows Specification) is a unified, composable architecture for managing Windows system configuration. Configuration is expressed in native PowerShell data structures, enabling full PowerShell ecosystem integration.
WinSpec simplifies your Windows workflow with Git-like commands:
| Daily Task | WinSpec Solution |
|---|---|
| Set up a new PC | Capture your configured system with pull, push to new machines |
| Keep config in sync | Use pull to capture system state, then push to apply |
| Apply your setup | Run push to apply your declarative config (safe, idempotent) |
| Check differences | Use diff to see what's changed between system and your config |
| Backup before changes | Use -Checkpoint to create restore points before applying |
| Rollback if needed | Use rollback to restore to a previous checkpoint |
| Principle | Description |
|---|---|
| Native | Configuration in PowerShell (.ps1), not YAML or JSON |
| Grouped | Directories only when necessary for organization |
| Composable | Import and merge specifications for modularity |
| Idempotent | Declarative state management - safe to run multiple times |
| Triggerable | One-time actions via explicit triggers |
WinSpec distinguishes between two types of providers:
| Type | Location | Characteristics | Idempotent | Examples |
|---|---|---|---|---|
| Declarative | managers/ |
State-based, testable | Yes | Registry, Service, Feature, Package |
| Trigger | triggers/ |
Action-based, fire-and-forget | No | Activation, Debloat, Office |
Declarative providers let you specify what state you want. Running multiple times produces the same result - the engine tests current state, calculates diff, and applies only needed changes.
Trigger providers let you specify what to trigger. These are explicitly named because they are NOT idempotent - users understand that triggering activation twice may have different effects than triggering once.
- Windows 10/11
- PowerShell 5.1 or PowerShell 7+
- Administrator privileges (for most operations)
# Add the bucket
scoop bucket add winspec https://github.com/lvyuemeng/winspec
# Install WinSpec
scoop install winspec
# Verify installation
winspec helpTo update WinSpec:
scoop update winspec-
Clone the repository:
git clone https://github.com/lvyuemeng/winspec.git cd winspec
-
(Optional) Run tests to verify installation:
.\winspec\tests\run-tests.ps1 -
Start using WinSpec:
.\winspec\winspec.ps1 help
Step 1: Pull system state to config
Capture your current system setup (or start fresh):
# Pull current system state to default location (~/.config/winspec/.winspec.ps1)
.\winspec\winspec.ps1 pull
# Or pull to specific file with template and comments
.\winspec\winspec.ps1 pull -Output my-config.ps1 -Template
# Interactive mode - choose what to include
.\winspec\winspec.ps1 pull -InteractiveStep 2: Push configuration to system
# Push a specification to system (declarative only, safe)
.\winspec\winspec.ps1 push -Spec .\myconfig.ps1
# Dry run (preview changes without applying)
.\winspec\winspec.ps1 push -Spec .\myconfig.ps1 -DryRun
# Push with checkpoint (create restore point first)
.\winspec\winspec.ps1 push -Spec .\myconfig.ps1 -Checkpoint
# Show current system state
.\winspec\winspec.ps1 statusStep 3: Daily maintenance
# See what's different between system and your config
.\winspec\winspec.ps1 diff -Spec .\myconfig.ps1
# Pull updated system state (capture new changes)
.\winspec\winspec.ps1 pull -Output my-updated-config.ps1
# If something goes wrong, rollback
.\winspec\winspec.ps1 rollback -Last| Command | Description |
|---|---|
| pull | Pull system state to config file (Git-like, primary) |
| push | Push config to system (Git-like, primary) |
| diff | Compare system state with a spec |
| merge | Merge two specification files |
| status | Show current system state |
trigger |
Execute a specific trigger |
rollback |
Rollback to a checkpoint |
providers |
List available providers |
validate |
Validate a spec without applying |
sandbox |
Test changes in a sandbox environment |
help |
Show help message |
# myconfig.ps1
@{
Name = "myconfig"
Description = "My Windows configuration"
# Import other specs (composition)
Import = @(
".\base-config.ps1"
)
# === DECLARATIVE PROVIDERS (Idempotent) ===
# Registry: fine-grained state management
Registry = @{
Clipboard = @{
EnableHistory = $true
}
Explorer = @{
ShowHidden = $true
ShowFileExt = $true
}
Theme = @{
AppTheme = "dark"
SystemTheme = "dark"
}
Desktop = @{
MenuShowDelay = "0"
}
}
# Windows Services
Service = @{
wuauserv = @{ State = "stopped"; Startup = "disabled" }
}
# Windows Features
Feature = @{
"Microsoft-Windows-Subsystem-Linux" = "enabled"
"VirtualMachinePlatform" = "enabled"
}
# === TRIGGERS (Non-Idempotent) ===
# Array of triggers to execute
Trigger = @(
@{ Name = "Activation" } # Run activation
@{ Name = "Debloat"; Value = "silent" } # Run debloat with option
@{ Name = "Office"; Value = "C:\Installers" } # Download Office to path
)
}WinSpec is modular - you can use only the providers you need. Simply omit the providers you don't want to configure:
# Only configure Registry - other providers will be ignored
@{
Name = "registry-only"
Registry = @{
Explorer = @{
ShowHidden = $true
}
}
}# Only configure Package - no Registry, Service, Feature, or Triggers
@{
Name = "packages-only"
Package = @{
Installed = @("git", "neovim")
}
}# Only use Triggers - no declarative providers
@{
Name = "triggers-only"
Trigger = @(
@{ Name = "Activation" }
)
}When pulling with specific providers:
# Pull only Registry and Package state (ignore Service, Feature)
winspec pull -Providers Registry,Package -Output my-config.ps1Daily Workflows:
# === New Machine Setup ===
# 1. On your configured machine: pull current system state
.\winspec\winspec.ps1 pull -Output my-setup.ps1
# 2. On new machine: push the configuration
.\winspec\winspec.ps1 push -Spec .\my-setup.ps1
# === Regular Maintenance ===
# Check if system matches your config
.\winspec\winspec.ps1 diff -Spec .\myconfig.ps1
# Pull updated system state (capture new changes)
.\winspec\winspec.ps1 pull -Output my-updated-config.ps1
# === Applying Changes ===
# Push with checkpoint (safe - creates restore point first)
.\winspec\winspec.ps1 push -Spec .\myconfig.ps1 -Checkpoint
# Dry run - see what would change
.\winspec\winspec.ps1 push -Spec .\myconfig.ps1 -DryRun
# If something goes wrong
.\winspec\winspec.ps1 rollback -Last
# === Other Commands ===
# Initialize a new configuration from current system state
.\winspec\winspec.ps1 init
# Run specific trigger(s)
.\winspec\winspec.ps1 trigger "activation"
.\winspec\winspec.ps1 trigger "activation", "debloat"
# Merge two config files
.\winspec\winspec.ps1 merge -Base base.ps1 -Incoming custom.ps1 -Output merged.ps1
# Validate a spec without applying
.\winspec\winspec.ps1 validate -Spec .\myconfig.ps1
# List available providers
.\winspec\winspec.ps1 providersTrigger providers download and execute remote scripts:
- Activation: Downloads from
https://get.activated.win - Debloat: Downloads from
https://debloat.raphi.re/ - Office: Downloads from Microsoft CDN
These scripts require administrator privileges. Always review remote scripts before execution. Use -DryRun to preview actions without executing them.
See LICENSE-MIT for details.
- docs/design.md - Architecture and design principles
- docs/spec.md - Specification and provider development guide
- docs/configuration.md - Configuration guide
- docs/contributing.md - Contributing guide
- docs/registry-reference.md - Registry provider details
- docs/service-reference.md - Service provider details
- docs/feature-reference.md - Feature provider details
WinSpec - Windows Configuration Made Simple