From 3f35a54e0a92844b3dc7122b6be01964cc987104 Mon Sep 17 00:00:00 2001 From: moons-14 Date: Wed, 29 Jul 2026 04:01:25 +0900 Subject: [PATCH] windows --- .gitignore | 4 +- windows/README.md | 383 +++++++++++++++++++++ windows/Scoopfile.json | 15 + windows/applications/chatgpt/apply.ps1 | 13 + windows/applications/git/apply.ps1 | 6 + windows/applications/git/gitconfig | 3 + windows/applications/vscode/apply.ps1 | 54 +++ windows/applications/vscode/argv.json | 3 + windows/applications/vscode/extensions.txt | 2 + windows/applications/vscode/settings.json | 5 + windows/configuration.dsc.yaml | 22 ++ windows/packages/winget.dsc.yaml | 37 ++ windows/system/explorer.dsc.yaml | 11 + windows/system/ime.dsc.yaml | 29 ++ windows/system/taskbar.dsc.yaml | 38 ++ windows/system/wallpaper/apply.ps1 | 32 ++ windows/system/wallpaper/wallpaper.theme | 21 ++ windows/update.ps1 | 19 + 18 files changed, 695 insertions(+), 2 deletions(-) create mode 100644 windows/README.md create mode 100644 windows/Scoopfile.json create mode 100644 windows/applications/chatgpt/apply.ps1 create mode 100644 windows/applications/git/apply.ps1 create mode 100644 windows/applications/git/gitconfig create mode 100644 windows/applications/vscode/apply.ps1 create mode 100644 windows/applications/vscode/argv.json create mode 100644 windows/applications/vscode/extensions.txt create mode 100644 windows/applications/vscode/settings.json create mode 100644 windows/configuration.dsc.yaml create mode 100644 windows/packages/winget.dsc.yaml create mode 100644 windows/system/explorer.dsc.yaml create mode 100644 windows/system/ime.dsc.yaml create mode 100644 windows/system/taskbar.dsc.yaml create mode 100644 windows/system/wallpaper/apply.ps1 create mode 100644 windows/system/wallpaper/wallpaper.theme create mode 100644 windows/update.ps1 diff --git a/.gitignore b/.gitignore index de6af78..e9a367b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,10 +23,10 @@ !/images/ !/secrets/ +!/windows/ + !/hosts/ - !/libs/ - !/modules/ !/tests/ diff --git a/windows/README.md b/windows/README.md new file mode 100644 index 0000000..d09097e --- /dev/null +++ b/windows/README.md @@ -0,0 +1,383 @@ +# Windows dotfiles + +This directory contains the Windows-specific configuration for this dotfiles +repository. + +The design has four layers: + +1. **Native package declarations** + - Scoop uses `Scoopfile.json`. + - WinGet / Microsoft Store packages use DSC `Microsoft.WinGet/Package`. +2. **Windows desired state** + - Windows settings use DSC resources grouped by settings domain. +3. **Application-owned configuration** + - Each application that needs files or CLI-based configuration has its own + directory and its own small `apply.ps1`. +4. **One root entry point** + - `update.ps1` only invokes the native package/configuration systems and the + application-specific apply scripts. + +The root script intentionally contains no application-specific paths, registry +logic, wallpaper loop, or VS Code extension list. + +## Layout + +```text +windows/ +├── README.md +├── update.ps1 +├── Scoopfile.json +├── configuration.dsc.yaml +│ +├── packages/ +│ └── winget.dsc.yaml +│ +├── system/ +│ ├── taskbar.dsc.yaml +│ ├── explorer.dsc.yaml +│ ├── ime.dsc.yaml +│ └── wallpaper/ +│ ├── apply.ps1 +│ └── wallpaper.theme +│ +└── applications/ + ├── chatgpt/ + │ └── apply.ps1 + ├── git/ + │ ├── apply.ps1 + │ └── gitconfig + │ + └── vscode/ + ├── apply.ps1 + ├── settings.json + ├── argv.json + └── extensions.txt +``` + +## Fresh Windows installation + +Open a normal, non-elevated PowerShell window. + +### 1. Allow local scripts + +```powershell +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +``` + +### 2. Install Scoop and bootstrap Git + +```powershell +Invoke-RestMethod https://get.scoop.sh | Invoke-Expression +scoop install git +``` + +### 3. Clone dotfiles + +```powershell +git clone https://github.com/moons-14/dotfiles.git "$HOME\dotfiles" +Set-Location "$HOME\dotfiles\windows" +``` + +### 4. Install Microsoft DSC v3 + +```powershell +winget install --id 9NVTPZWRC6KQ --source msstore +``` + +If `dsc` is not available in the current shell immediately after installation, +open a new PowerShell window and return to: + +```powershell +Set-Location "$HOME\dotfiles\windows" +``` + +### 5. Apply everything + +```powershell +.\update.ps1 +``` + +## Normal workflow + +```powershell +Set-Location "$HOME\dotfiles\windows" + +git pull +.\update.ps1 +``` + +`update.ps1` stays intentionally small: + +```powershell +scoop update +scoop import .\Scoopfile.json +scoop update * + +dsc config set --file .\configuration.dsc.yaml + +& .\applications\chatgpt\apply.ps1 +& .\applications\git\apply.ps1 +& .\applications\vscode\apply.ps1 +& .\system\wallpaper\apply.ps1 +``` + +The specialized scripts own the details of their own configuration. + +## Packages + +### Scoop + +`Scoopfile.json` currently declares: + +- Git + +The update entry point: + +1. updates Scoop and bucket metadata +2. imports `Scoopfile.json` so newly declared packages are installed +3. updates all applications installed through Scoop + +### WinGet / Microsoft Store + +`packages/winget.dsc.yaml` manages: + +- Google Chrome +- 1Password +- Visual Studio Code +- Vesktop (`Vencord.Vesktop`) +- 7-Zip + +ChatGPT is intentionally not part of this DSC file because its Microsoft Store +installation requires explicit package/source agreement acceptance. + +### ChatGPT + +`applications/chatgpt/apply.ps1` uses OpenAI's documented WinGet installation: + +```powershell +winget install ` + --id 9NT1R1C2HH7J ` + --source msstore ` + --accept-package-agreements ` + --accept-source-agreements ` + --silent ` + --disable-interactivity +``` + +The Store product ID `9NT1R1C2HH7J` is the ChatGPT Windows app. The previously +used `9PLM9XGG6VKS` ID is not used here. + +7-Zip is intentionally installed with its normal Windows installer through +WinGet rather than as a portable Scoop package, because the normal installer +provides Explorer shell integration. + +## Windows settings + +### Taskbar + +`system/taskbar.dsc.yaml` configures: + +- Widgets: off +- Resume: off +- Search: icon only +- Alignment: left + +### Explorer + +`system/explorer.dsc.yaml` configures: + +- show known file extensions + +7-Zip context-menu integration is left to the official 7-Zip installer. No +unsupported Explorer context-menu patches are applied. + +### Microsoft IME + +`system/ime.dsc.yaml` configures: + +- Muhenkan: IME Off +- Henkan: IME On + +## Git + +Git's user configuration lives in: + +```text +applications/git/gitconfig +``` + +It currently contains: + +```ini +[user] + name = moons-14 + email = moons@moons14.com +``` + +`applications/git/apply.ps1` copies this file to: + +```text +%USERPROFILE%\.gitconfig +``` + +This means the repository is the source of truth for the managed global Git +configuration. Add future Git settings to `applications/git/gitconfig`, not to +`update.ps1`. + +## Visual Studio Code + +VS Code configuration lives entirely under: + +```text +applications/vscode/ +``` + +### `settings.json` + +Minimal editor defaults: + +- no startup welcome editor +- format on save +- final newline + +### `argv.json` + +Sets the VS Code UI locale to Japanese: + +```json +{ + "locale": "ja" +} +``` + +### `extensions.txt` + +One Marketplace extension ID per line. + +Currently: + +```text +MS-CEINTL.vscode-language-pack-ja +``` + +`applications/vscode/apply.ps1` copies the config files and uses the official +VS Code CLI. It first checks `code --list-extensions`, installs only missing +declared extensions, then runs `code --update-extensions`. + +To add another extension, only edit `extensions.txt`. + +## Wallpaper + +Wallpaper management lives under: + +```text +system/wallpaper/ +``` + +`apply.ps1` synchronizes: + +```text +https://github.com/moons-14/wallpapers +``` + +to: + +```text +%USERPROFILE%\.wallpaper +``` + +The slideshow itself is not implemented in PowerShell. + +`wallpaper.theme` uses the native Windows slideshow mechanism: + +```ini +[Slideshow] +Interval=60000 +Shuffle=1 +ImagesRootPath=%USERPROFILE%\.wallpaper +``` + +Windows therefore performs the one-minute randomized rotation. The script only +keeps the Git repository and theme declaration synchronized. + +The theme also contains the required Windows theme validity marker: + +```ini +[MasterThemeSelector] +MTSM=DABJDKT +``` + +Without this section, Windows rejects the `.theme` file instead of applying it. + +## Adding an application + +### Package only + +If it belongs in Scoop `main`, add it to: + +```text +Scoopfile.json +``` + +Otherwise add a `Microsoft.WinGet/Package` resource to: + +```text +packages/winget.dsc.yaml +``` + +No PowerShell file is necessary when installation is the only requirement. + +### Package with configuration + +If an application needs managed files or its own CLI, create: + +```text +applications// +├── apply.ps1 +└── +``` + +Then add only one call to the root `update.ps1`: + +```powershell +& .\applications\\apply.ps1 +``` + +Keep all application-specific logic inside that directory. + +## Adding a Windows setting + +Settings that can be represented as DSC belong under `system/` and should be +grouped by responsibility: + +```text +system/taskbar.dsc.yaml +system/explorer.dsc.yaml +system/ime.dsc.yaml +system/privacy.dsc.yaml +``` + +When adding a new DSC document, include it from `configuration.dsc.yaml`. + +If a system feature cannot be expressed reliably with DSC and genuinely needs +procedural setup, give that feature its own directory, following the wallpaper +pattern: + +```text +system// +├── apply.ps1 +└── ... +``` + +Do not add feature-specific logic directly to `update.ps1`. + +## Design rules + +- Prefer a tool's native declaration/configuration format. +- Prefer DSC for Windows desired state. +- Keep application-specific procedural work beside the application. +- Keep system-specific procedural work beside the system feature. +- Keep `update.ps1` as an orchestration list, not a configuration engine. +- Do not duplicate package lists in PowerShell. +- Avoid background PowerShell loops, Scheduled Tasks, and registry hacks when a + stable application or Windows mechanism already exists. diff --git a/windows/Scoopfile.json b/windows/Scoopfile.json new file mode 100644 index 0000000..577dbc0 --- /dev/null +++ b/windows/Scoopfile.json @@ -0,0 +1,15 @@ +{ + "buckets": [ + { + "Name": "main", + "Source": "https://github.com/ScoopInstaller/Main" + } + ], + "apps": [ + { + "Name": "git", + "Source": "main", + "Info": "" + } + ] +} diff --git a/windows/applications/chatgpt/apply.ps1 b/windows/applications/chatgpt/apply.ps1 new file mode 100644 index 0000000..a985a52 --- /dev/null +++ b/windows/applications/chatgpt/apply.ps1 @@ -0,0 +1,13 @@ +$ErrorActionPreference = "Stop" + +winget install ` + --id 9PLM9XGG6VKS ` + --source msstore ` + --accept-package-agreements ` + --accept-source-agreements ` + --silent ` + --disable-interactivity + +if ($LASTEXITCODE -ne 0) { + throw "Failed to install or update ChatGPT." +} diff --git a/windows/applications/git/apply.ps1 b/windows/applications/git/apply.ps1 new file mode 100644 index 0000000..327a97b --- /dev/null +++ b/windows/applications/git/apply.ps1 @@ -0,0 +1,6 @@ +$ErrorActionPreference = "Stop" + +$source = Join-Path $PSScriptRoot "gitconfig" +$target = Join-Path $HOME ".gitconfig" + +Copy-Item $source $target -Force diff --git a/windows/applications/git/gitconfig b/windows/applications/git/gitconfig new file mode 100644 index 0000000..e7dbbcc --- /dev/null +++ b/windows/applications/git/gitconfig @@ -0,0 +1,3 @@ +[user] + name = moons-14 + email = moons@moons14.com diff --git a/windows/applications/vscode/apply.ps1 b/windows/applications/vscode/apply.ps1 new file mode 100644 index 0000000..9dbef0b --- /dev/null +++ b/windows/applications/vscode/apply.ps1 @@ -0,0 +1,54 @@ +$ErrorActionPreference = "Stop" + +$userDir = Join-Path $env:APPDATA "Code\User" +$runtimeDir = Join-Path $HOME ".vscode" + +New-Item -ItemType Directory -Force -Path $userDir, $runtimeDir | Out-Null + +Copy-Item (Join-Path $PSScriptRoot "settings.json") ` + (Join-Path $userDir "settings.json") -Force + +Copy-Item (Join-Path $PSScriptRoot "argv.json") ` + (Join-Path $runtimeDir "argv.json") -Force + +$codeCandidates = @( + (Join-Path $env:LOCALAPPDATA "Programs\Microsoft VS Code\bin\code.cmd"), + (Join-Path $env:ProgramFiles "Microsoft VS Code\bin\code.cmd") +) + +$code = $codeCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 + +if (-not $code) { + $command = Get-Command code.cmd -ErrorAction SilentlyContinue + if ($command) { + $code = $command.Source + } +} + +if (-not $code) { + throw "VS Code CLI was not found." +} + +$installedExtensions = @( + & $code --list-extensions | + ForEach-Object { $_.Trim().ToLowerInvariant() } +) + +Get-Content (Join-Path $PSScriptRoot "extensions.txt") | + Where-Object { $_.Trim() -and -not $_.Trim().StartsWith("#") } | + ForEach-Object { + $extension = $_.Trim() + + if ($installedExtensions -notcontains $extension.ToLowerInvariant()) { + & $code --install-extension $extension + + if ($LASTEXITCODE -ne 0) { + throw "Failed to install VS Code extension: $extension" + } + } + } + +& $code --update-extensions +if ($LASTEXITCODE -ne 0) { + throw "Failed to update VS Code extensions." +} diff --git a/windows/applications/vscode/argv.json b/windows/applications/vscode/argv.json new file mode 100644 index 0000000..fea8d06 --- /dev/null +++ b/windows/applications/vscode/argv.json @@ -0,0 +1,3 @@ +{ + "locale": "ja" +} diff --git a/windows/applications/vscode/extensions.txt b/windows/applications/vscode/extensions.txt new file mode 100644 index 0000000..3179179 --- /dev/null +++ b/windows/applications/vscode/extensions.txt @@ -0,0 +1,2 @@ +# One Visual Studio Code Marketplace extension ID per line. +MS-CEINTL.vscode-language-pack-ja diff --git a/windows/applications/vscode/settings.json b/windows/applications/vscode/settings.json new file mode 100644 index 0000000..64a965d --- /dev/null +++ b/windows/applications/vscode/settings.json @@ -0,0 +1,5 @@ +{ + "workbench.startupEditor": "none", + "editor.formatOnSave": true, + "files.insertFinalNewline": true +} diff --git a/windows/configuration.dsc.yaml b/windows/configuration.dsc.yaml new file mode 100644 index 0000000..429741a --- /dev/null +++ b/windows/configuration.dsc.yaml @@ -0,0 +1,22 @@ +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + +resources: + - name: WinGet packages + type: Microsoft.DSC/Include + properties: + configurationFile: packages/winget.dsc.yaml + + - name: Taskbar + type: Microsoft.DSC/Include + properties: + configurationFile: system/taskbar.dsc.yaml + + - name: Explorer + type: Microsoft.DSC/Include + properties: + configurationFile: system/explorer.dsc.yaml + + - name: Microsoft IME + type: Microsoft.DSC/Include + properties: + configurationFile: system/ime.dsc.yaml diff --git a/windows/packages/winget.dsc.yaml b/windows/packages/winget.dsc.yaml new file mode 100644 index 0000000..87d1dc3 --- /dev/null +++ b/windows/packages/winget.dsc.yaml @@ -0,0 +1,37 @@ +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + +resources: + - name: Google Chrome + type: Microsoft.WinGet/Package + properties: + id: Google.Chrome + source: winget + useLatest: true + + - name: 1Password + type: Microsoft.WinGet/Package + properties: + id: AgileBits.1Password + source: winget + useLatest: true + + - name: Visual Studio Code + type: Microsoft.WinGet/Package + properties: + id: Microsoft.VisualStudioCode + source: winget + useLatest: true + + - name: Vesktop + type: Microsoft.WinGet/Package + properties: + id: Vencord.Vesktop + source: winget + useLatest: true + + - name: 7-Zip + type: Microsoft.WinGet/Package + properties: + id: 7zip.7zip + source: winget + useLatest: true diff --git a/windows/system/explorer.dsc.yaml b/windows/system/explorer.dsc.yaml new file mode 100644 index 0000000..06160cd --- /dev/null +++ b/windows/system/explorer.dsc.yaml @@ -0,0 +1,11 @@ +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + +resources: + - name: Show file extensions + type: Microsoft.Windows/Registry + properties: + keyPath: HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced + valueName: HideFileExt + valueData: + DWord: 0 + _exist: true diff --git a/windows/system/ime.dsc.yaml b/windows/system/ime.dsc.yaml new file mode 100644 index 0000000..ee4a303 --- /dev/null +++ b/windows/system/ime.dsc.yaml @@ -0,0 +1,29 @@ +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + +resources: + - name: IME Key Assignment + type: Microsoft.Windows/Registry + properties: + keyPath: HKCU\Software\Microsoft\IME\15.0\IMEJP\MSIME + valueName: IsKeyAssignmentEnabled + valueData: + DWord: 1 + _exist: true + + - name: Muhenkan IME Off + type: Microsoft.Windows/Registry + properties: + keyPath: HKCU\Software\Microsoft\IME\15.0\IMEJP\MSIME + valueName: KeyAssignmentMuhenkan + valueData: + DWord: 1 + _exist: true + + - name: Henkan IME On + type: Microsoft.Windows/Registry + properties: + keyPath: HKCU\Software\Microsoft\IME\15.0\IMEJP\MSIME + valueName: KeyAssignmentHenkan + valueData: + DWord: 0 + _exist: true diff --git a/windows/system/taskbar.dsc.yaml b/windows/system/taskbar.dsc.yaml new file mode 100644 index 0000000..7f5955d --- /dev/null +++ b/windows/system/taskbar.dsc.yaml @@ -0,0 +1,38 @@ +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + +resources: + - name: Taskbar Widgets + type: Microsoft.Windows/Registry + properties: + keyPath: HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced + valueName: TaskbarDa + valueData: + DWord: 0 + _exist: true + + - name: Taskbar Resume + type: Microsoft.Windows/Registry + properties: + keyPath: HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced + valueName: IsEnabled + valueData: + DWord: 0 + _exist: true + + - name: Taskbar Search + type: Microsoft.Windows/Registry + properties: + keyPath: HKCU\Software\Microsoft\Windows\CurrentVersion\Search + valueName: SearchboxTaskbarMode + valueData: + DWord: 1 + _exist: true + + - name: Taskbar Alignment + type: Microsoft.Windows/Registry + properties: + keyPath: HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced + valueName: TaskbarAl + valueData: + DWord: 0 + _exist: true diff --git a/windows/system/wallpaper/apply.ps1 b/windows/system/wallpaper/apply.ps1 new file mode 100644 index 0000000..f5851aa --- /dev/null +++ b/windows/system/wallpaper/apply.ps1 @@ -0,0 +1,32 @@ +$ErrorActionPreference = "Stop" + +$wallpaperDir = Join-Path $HOME ".wallpaper" + +if (Test-Path (Join-Path $wallpaperDir ".git")) { + git -C $wallpaperDir pull --ff-only +} +elseif (-not (Test-Path $wallpaperDir)) { + git clone https://github.com/moons-14/wallpapers.git $wallpaperDir +} +else { + throw "$wallpaperDir exists but is not a Git repository." +} + +if ($LASTEXITCODE -ne 0) { + throw "Failed to synchronize the wallpaper repository." +} + +$themeDir = Join-Path $env:LOCALAPPDATA "Microsoft\Windows\Themes" +$themeTarget = Join-Path $themeDir "moons-wallpaper.theme" + +New-Item -ItemType Directory -Force -Path $themeDir | Out-Null +Copy-Item (Join-Path $PSScriptRoot "wallpaper.theme") $themeTarget -Force + +$currentTheme = (Get-ItemProperty ` + "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes" ` + -Name CurrentTheme ` + -ErrorAction SilentlyContinue).CurrentTheme + +if ($currentTheme -ne $themeTarget) { + Start-Process $themeTarget +} diff --git a/windows/system/wallpaper/wallpaper.theme b/windows/system/wallpaper/wallpaper.theme new file mode 100644 index 0000000..2b8409a --- /dev/null +++ b/windows/system/wallpaper/wallpaper.theme @@ -0,0 +1,21 @@ +[Theme] +DisplayName=Moons Wallpapers + +[Slideshow] +Interval=60000 +Shuffle=1 +ImagesRootPath=%USERPROFILE%\.wallpaper + +[Control Panel\Desktop] +TileWallpaper=0 +WallpaperStyle=10 +Pattern= + +[VisualStyles] +Path=%SystemRoot%\resources\themes\Aero\Aero.msstyles +ColorStyle=NormalColor +Size=NormalSize +Transparency=1 + +[MasterThemeSelector] +MTSM=DABJDKT diff --git a/windows/update.ps1 b/windows/update.ps1 new file mode 100644 index 0000000..bc2128e --- /dev/null +++ b/windows/update.ps1 @@ -0,0 +1,19 @@ +$ErrorActionPreference = "Stop" + +Push-Location $PSScriptRoot + +try { + scoop update + scoop import .\Scoopfile.json + scoop update * + + dsc config set --file .\configuration.dsc.yaml + + & .\applications\chatgpt\apply.ps1 + & .\applications\git\apply.ps1 + & .\applications\vscode\apply.ps1 + & .\system\wallpaper\apply.ps1 +} +finally { + Pop-Location +}