|
| 1 | +# What is it |
| 2 | + |
| 3 | +We would like to enable our users to use [`winget configure`](https://learn.microsoft.com/en-us/windows/package-manager/winget/configure) command to install PowerToys and configure its settings with a [Winget configuration file](https://learn.microsoft.com/en-us/windows/package-manager/configuration/create). For example: |
| 4 | + |
| 5 | +```yaml |
| 6 | +properties: |
| 7 | + resources: |
| 8 | + - resource: Microsoft.WinGet.DSC/WinGetPackage |
| 9 | + directives: |
| 10 | + description: Install PowerToys |
| 11 | + allowPrerelease: true |
| 12 | + settings: |
| 13 | + id: PowerToys (Preview) |
| 14 | + source: winget |
| 15 | + |
| 16 | + - resource: PowerToysConfigure |
| 17 | + directives: |
| 18 | + description: Configure PowerToys |
| 19 | + settings: |
| 20 | + ShortcutGuide: |
| 21 | + Enabled: false |
| 22 | + OverlayOpacity: 1 |
| 23 | + FancyZones: |
| 24 | + Enabled: true |
| 25 | + FancyzonesEditorHotkey: "Shift+Ctrl+Alt+F" |
| 26 | + configurationVersion: 0.2.0 |
| 27 | +``` |
| 28 | +
|
| 29 | +This should install PowerToys and make `PowerToysConfigure` resource available. We can use it in the same file. |
| 30 | + |
| 31 | +# How it works |
| 32 | + |
| 33 | +`PowerToysConfigure` is a [class-based DSC resource](https://learn.microsoft.com/en-us/powershell/dsc/concepts/class-based-resources?view=dsc-2.0). It looks up whether each setting was specified or not by checking whether it's `$null` or `0` for `enum`s and invokes `PowerToys.Settings.exe` with the updated value like so: |
| 34 | +``` |
| 35 | +PowerToys.Settings.exe set <ModuleName>.<SettingName> <SettingValue> |
| 36 | +``` |
| 37 | + |
| 38 | +So for the example the config above should perform 3 following invocations: |
| 39 | +``` |
| 40 | +PowerToys.Settings.exe set ShortcutGuide.Enabled false |
| 41 | +PowerToys.Settings.exe set FancyZones.Enabled true |
| 42 | +PowerToys.Settings.exe set FancyZones.FancyzonesEditorHotkey "Shift+Ctrl+Alt+F" |
| 43 | +``` |
| 44 | + |
| 45 | +`PowerToys.Settings` uses dotnet reflection capabilities to determine `SettingName` type and tries to convert the supplied `SettingValue` string accordingly. We use `ICmdReprParsable` for custom setting types. |
| 46 | + |
| 47 | + |
| 48 | +# How DSC is implemented |
| 49 | + |
| 50 | +We use `PowerToys.Settings.DSC.Schema.Generator` to generate the bulk of `PowerToysConfigure.psm1` file. It also uses dotnet reflection capabilities to inspect `PowerToys.Settings.UI.Lib.dll` assembly and generate properties for the modules we have. The actual generation is done as a `PowerToys.Settings.DSC.Schema.Generator.csproj` post-build action. |
| 51 | + |
| 52 | +# Debugging DSC resources |
| 53 | + |
| 54 | +First, make sure that PowerShell 7.4+ is installed. Then make sure that you have DSC installed: |
| 55 | + |
| 56 | +```ps |
| 57 | +Install-Module -Name PSDesiredStateConfiguration -RequiredVersion 2.0.7 |
| 58 | +``` |
| 59 | + |
| 60 | +After that, start a new `pwsh` session and `cd` to `src\dsc\Microsoft.PowerToys.Configure\Generated` directory. From there, you should execute: |
| 61 | +```ps |
| 62 | +$env:PSModulePath += ";$pwd" |
| 63 | +``` |
| 64 | + |
| 65 | +Now build `PowerToys.sln` and **move** `src\dsc\Microsoft.PowerToys.Configure\Microsoft.PowerToys.Configure.psd1` temporarily to `src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\0.0.1\` folder, so it's located alongside with the generated `Microsoft.PowerToys.Configure.psm1`. |
| 66 | + |
| 67 | +This will allow DSC to discover our DSC Resource module. See [PSModulePath](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_psmodulepath?view=powershell-7.4#long-description) for more info. |
| 68 | + |
| 69 | +If everything works, you should see that your module is discovered by executing the following command: |
| 70 | + |
| 71 | +```ps |
| 72 | +Get-Module -ListAvailable | grep PowerToys |
| 73 | +``` |
| 74 | + |
| 75 | +The resource itself should also be available: |
| 76 | +```ps |
| 77 | +Get-DSCResource | grep PowerToys |
| 78 | +``` |
| 79 | + |
| 80 | +Otherwise, you can force-import the module to diagnose issues: |
| 81 | + |
| 82 | +``` |
| 83 | +Import-Module .\Microsoft.PowerToys.Configure.psd1 |
| 84 | +``` |
| 85 | + |
| 86 | +If it's imported successfully, you could also try to invoke it directly: |
| 87 | + |
| 88 | +```ps |
| 89 | +Invoke-DscResource -Name PowerToysConfigure -Method Set -ModuleName Microsoft.PowerToys.Configure -Property @{ Debug = $true; Awake = @{ Enabled = $false; Mode = "TIMED"; IntervalMinutes = "10" } } |
| 90 | +``` |
| 91 | + |
| 92 | +Note that we've supplied `Debug` option, so a `%TEMP\PowerToys.DSC.TestConfigure.txt` is created with the supplied properties, a current timestamp, and other debug output. |
| 93 | + |
| 94 | +Finally, you can test it with winget by invoking it as such: |
| 95 | + |
| 96 | +```ps |
| 97 | +winget configure .\configuration.dsc.yaml --accept-configuration-agreements --disable-interactivity |
| 98 | +``` |
0 commit comments