diff --git a/README.md b/README.md index 249d4ad7..1cb78b44 100644 --- a/README.md +++ b/README.md @@ -63,11 +63,11 @@ First, get the files onto the box. The config is invoked from a local path, but ```powershell # Git already installed: -git clone https://github.com/microsoft/WindowsDeveloperConfig.git +git clone https://github.com/OnlyBMan/WindowsDeveloperConfig.git cd WindowsDeveloperConfig # Otherwise, download and extract the ZIP: -Invoke-WebRequest -Uri https://github.com/microsoft/WindowsDeveloperConfig/archive/refs/heads/main.zip -OutFile WindowsDeveloperConfig.zip +Invoke-WebRequest -Uri https://github.com/OnlyBMan/WindowsDeveloperConfig/archive/refs/heads/main.zip -OutFile WindowsDeveloperConfig.zip Expand-Archive .\WindowsDeveloperConfig.zip -DestinationPath . cd .\WindowsDeveloperConfig-main ``` @@ -226,7 +226,7 @@ WSL needs hardware virtualization available to the OS. Two common root causes: ## 🐛 Reporting issues -Hit a bug, a stale doc, or a setup that fails on your machine? Open an issue at [github.com/microsoft/WindowsDeveloperConfig/issues](https://github.com/microsoft/WindowsDeveloperConfig/issues). Include your Windows build (`winver`), the exact command you ran, and the failing output. This helps us triage faster. +Hit a bug, a stale doc, or a setup that fails on your machine? Open an issue at [github.com/OnlyBMan/WindowsDeveloperConfig/issues](https://github.com/OnlyBMan/WindowsDeveloperConfig/issues). Include your Windows build (`winver`), the exact command you ran, and the failing output. This helps us triage faster.
diff --git a/windows-dev-config/assets/wallpaper.png b/windows-dev-config/assets/wallpaper.png new file mode 100644 index 00000000..d5f087ee Binary files /dev/null and b/windows-dev-config/assets/wallpaper.png differ diff --git a/windows-dev-config/dev-config.winget b/windows-dev-config/dev-config.winget index 3cba5d90..8b409ec9 100644 --- a/windows-dev-config/dev-config.winget +++ b/windows-dev-config/dev-config.winget @@ -633,6 +633,18 @@ resources: description: Disable sync provider notifications (tips) securityContext: elevated +# Disable checkboxes on file/folder icons in Explorer +- type: Microsoft.Windows/Registry + name: DisableCheckboxes + properties: + keyPath: HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced + valueName: AutoCheckSelect + valueData: + DWord: 0 + metadata: + description: Disable item checkboxes in File Explorer + securityContext: elevated + # ============================================================================= # Notifications and Lock Screen # ============================================================================= @@ -684,7 +696,19 @@ resources: valueData: DWord: 1 metadata: - description: Enable "End Task" on right-click of taskbar icons + description: Enable "End Task" on right-click of taskbar icons + securityContext: elevated + +# Taskbar left-align (0 = left, 1 = center) +- type: Microsoft.Windows/Registry + name: TaskbarLeftAlign + properties: + keyPath: HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced + valueName: TaskbarAl + valueData: + DWord: 0 + metadata: + description: Align taskbar icons to the left securityContext: elevated # ============================================================================= @@ -902,6 +926,26 @@ resources: metadata: description: Install PowerToys (Optional) +- type: Microsoft.WinGet/Package + name: Brave + properties: + id: Brave.Brave + source: winget + useLatest: true + installMode: silent + metadata: + description: Install Brave Browser + +- type: Microsoft.WinGet/Package + name: ClaudeCode + properties: + id: Anthropic.ClaudeCode + source: winget + useLatest: true + installMode: silent + metadata: + description: Install Anthropic Claude Code + - type: Microsoft.Windows/Registry name: PowerToysAOT dependsOn: @@ -1035,3 +1079,348 @@ resources: copilot plugin install winui@win-dev-skills metadata: description: Install the WinUI Copilot plugin from win-dev-skills + +# ============================================================================= +# Set Desktop Wallpaper +# Copies the wallpaper from the config directory and applies it. +# ============================================================================= +- type: Microsoft.DSC.Transitional/PowerShellScript + name: SetWallpaper + properties: + getScript: | + Add-Type -TypeDefinition @' + using System.Runtime.InteropServices; + public class Wallpaper { + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); + } + '@ + $wallpaperPath = [Environment]::GetFolderPath('CommonApplicationData') + '\DevConfig\wallpaper.png' + $current = (Get-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name WallPaper -EA SilentlyContinue).WallPaper + return @{ wallpaperPath = $current } + testScript: | + $wallpaperPath = [Environment]::GetFolderPath('CommonApplicationData') + '\DevConfig\wallpaper.png' + $current = (Get-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name WallPaper -EA SilentlyContinue).WallPaper + return ($current -eq $wallpaperPath) + setScript: | + $sourceFile = "${WinGetConfigRoot}\assets\wallpaper.png" + if (-not (Test-Path $sourceFile)) { + Write-Warning "Wallpaper image not found at $sourceFile" + return + } + $destDir = Join-Path ([Environment]::GetFolderPath('CommonApplicationData')) 'DevConfig' + New-Item -ItemType Directory -Path $destDir -Force | Out-Null + $destFile = Join-Path $destDir 'wallpaper.png' + Copy-Item $sourceFile $destFile -Force + + Add-Type -TypeDefinition @' + using System.Runtime.InteropServices; + public class Wallpaper { + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); + } + '@ + $SPI_SETDESKWALLPAPER = 20 + $SPIF_UPDATEINIFILE = 0x01 + $SPIF_SENDCHANGE = 0x02 + [Wallpaper]::SystemParametersInfo($SPI_SETDESKWALLPAPER, 0, $destFile, $SPIF_UPDATEINIFILE -bor $SPIF_SENDCHANGE) + Write-Host "Wallpaper set to $destFile" + metadata: + description: Set the desktop wallpaper + +# ============================================================================= +# Taskbar Pins — unpin Edge, pin Brave +# ============================================================================= +- type: Microsoft.DSC.Transitional/PowerShellScript + name: TaskbarPins + dependsOn: + - Brave + properties: + getScript: | + $taskbarPath = "$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar" + $edgePinned = Test-Path "$taskbarPath\Microsoft Edge.lnk" + $bravePinned = Test-Path "$taskbarPath\Brave.lnk" + return @{ edgePinned = $edgePinned; bravePinned = $bravePinned } + testScript: | + $taskbarPath = "$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar" + $edgePinned = Test-Path "$taskbarPath\Microsoft Edge.lnk" + $bravePinned = Test-Path "$taskbarPath\Brave.lnk" + return (-not $edgePinned -and $bravePinned) + setScript: | + # Unpin Microsoft Edge using shell:taskbar pin removal + $edgeLink = "$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Microsoft Edge.lnk" + if (Test-Path $edgeLink) { + Remove-Item $edgeLink -Force + Write-Host "Unpinned Microsoft Edge from taskbar" + } + + # Pin Brave using shell:appsfolder method (more reliable) + $braveExe = "${env:ProgramFiles}\BraveSoftware\Brave-Browser\Application\brave.exe" + if (Test-Path $braveExe) { + # Create shortcut in the taskbar folder + $taskbarPath = "$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar" + if (!(Test-Path $taskbarPath)) { + New-Item -ItemType Directory -Path $taskbarPath -Force | Out-Null + } + + $shell = New-Object -ComObject Shell.Application + $folder = $shell.Namespace($taskbarPath) + $shortcut = $folder.ParseName("Brave.lnk") + if ($shortcut) { + # Already exists + Write-Host "Brave already pinned" + } else { + # Pin using the application path + $shell = New-Object -ComObject WScript.Shell + $shortcut = $shell.CreateShortcut((Join-Path $taskbarPath 'Brave.lnk')) + $shortcut.TargetPath = $braveExe + $shortcut.WorkingDirectory = Split-Path $braveExe -Parent + $shortcut.Save() + Write-Host "Pinned Brave to taskbar" + } + } else { + Write-Warning "Brave executable not found at $braveExe" + } + + # Restart explorer to apply changes (force restart) + Stop-Process -Name explorer -Force + Start-Sleep -Seconds 2 + Start-Process explorer.exe + Write-Host "Explorer restarted to apply taskbar changes" + metadata: + description: Unpin Edge and pin Brave to the taskbar + securityContext: elevated +# ============================================================================= +# Visual Studio 2026 Enterprise with C++ and C# workloads +# ============================================================================= +- type: Microsoft.DSC.Transitional/PowerShellScript + name: VisualStudio2026 + properties: + getScript: | + $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + + if (-not (Test-Path $vsWhere)) { + return @{ + installed = $false + workloadsComplete = $false + installationPath = $null + } + } + + $instance = & $vsWhere ` + -latest ` + -products Microsoft.VisualStudio.Product.Enterprise ` + -property installationPath 2>$null + + if (-not $instance) { + return @{ + installed = $false + workloadsComplete = $false + installationPath = $null + } + } + + $completeValue = & $vsWhere ` + -latest ` + -products Microsoft.VisualStudio.Product.Enterprise ` + -requires Microsoft.VisualStudio.Workload.NativeDesktop Microsoft.VisualStudio.Workload.ManagedDesktop ` + -property isComplete 2>$null + + return @{ + installed = [bool]$instance + workloadsComplete = ($completeValue -eq '1') + installationPath = $instance + } + + testScript: | + $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + + if (-not (Test-Path $vsWhere)) { + return $false + } + + $completeValue = & $vsWhere ` + -latest ` + -products Microsoft.VisualStudio.Product.Enterprise ` + -requires Microsoft.VisualStudio.Workload.NativeDesktop Microsoft.VisualStudio.Workload.ManagedDesktop ` + -property isComplete 2>$null + + return ($completeValue -eq '1') + + setScript: | + $ErrorActionPreference = 'Stop' + + $logFile = Join-Path $env:TEMP "vs-install-wrapper-$(Get-Date -Format 'yyyyMMdd-HHmmss').log" + + function Write-Log { + param([string]$Message) + + $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' + $line = "[$timestamp] $Message" + + Write-Host $line + Add-Content -Path $logFile -Value $line + } + + function Get-LatestVsLogs { + Get-ChildItem $env:TEMP -File -ErrorAction SilentlyContinue | + Where-Object { + $_.Name -like 'dd_bootstrapper*' -or + $_.Name -like 'dd_client*' -or + $_.Name -like 'dd_setup*' -or + $_.Name -like 'vs-install-wrapper-*' + } | + Sort-Object LastWriteTime -Descending | + Select-Object -First 20 | + ForEach-Object { $_.FullName } + } + + function Throw-WithVsLogs { + param( + [string]$Message, + [int]$ExitCode + ) + + $logs = Get-LatestVsLogs + $logText = if ($logs) { $logs -join "`n" } else { '(no VS logs found in TEMP)' } + + throw "$Message Exit code: $ExitCode`nWrapper log: $logFile`nRecent VS logs:`n$logText" + } + + Write-Log "Starting Visual Studio 2026 Enterprise install/configure." + Write-Log "Wrapper log: $logFile" + + # Visual Studio installer operations can fail if VS or installer processes are already running. + $blockingProcesses = @( + 'devenv', + 'VSIXInstaller', + 'setup', + 'vs_installer', + 'ServiceHub.Host.AnyCPU', + 'ServiceHub.Host.dotnet.x64' + ) + + $running = Get-Process -ErrorAction SilentlyContinue | + Where-Object { $blockingProcesses -contains $_.ProcessName } + + if ($running) { + Write-Log "Stopping existing Visual Studio/installer processes..." + $running | Stop-Process -Force -ErrorAction SilentlyContinue + Start-Sleep -Seconds 5 + } + + $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $setupExe = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe" + + # If Enterprise is already installed, modify that instance using setup.exe. + if ((Test-Path $vsWhere) -and (Test-Path $setupExe)) { + $instance = & $vsWhere ` + -latest ` + -products Microsoft.VisualStudio.Product.Enterprise ` + -property installationPath 2>$null + + if ($instance) { + Write-Log "Visual Studio Enterprise already installed at: $instance" + Write-Log "Adding required workloads using setup.exe modify..." + + Push-Location $env:TEMP + try { + $args = @( + 'modify', + '--installPath', $instance, + '--add', 'Microsoft.VisualStudio.Workload.NativeDesktop', + '--add', 'Microsoft.VisualStudio.Workload.ManagedDesktop', + '--includeRecommended', + '--quiet', + '--norestart', + '--wait' + ) + + Write-Log "Running: $setupExe $($args -join ' ')" + + $p = Start-Process ` + -FilePath $setupExe ` + -ArgumentList $args ` + -WorkingDirectory $env:TEMP ` + -Wait ` + -PassThru + + Write-Log "Visual Studio modify exit code: $($p.ExitCode)" + } + finally { + Pop-Location + } + + if ($p.ExitCode -eq 0 -or $p.ExitCode -eq 3010 -or $p.ExitCode -eq 1641) { + Write-Log "Visual Studio workloads configured successfully." + return + } + + Throw-WithVsLogs -Message "Visual Studio modify failed." -ExitCode $p.ExitCode + } + } + + # Fresh install via official VS 2026 Enterprise bootstrapper. + $vsBootstrapper = Join-Path $env:TEMP 'vs_enterprise_2026.exe' + $bootstrapperUrl = 'https://aka.ms/vs/18/Stable/vs_enterprise.exe' + + Write-Log "Visual Studio Enterprise not found. Downloading bootstrapper..." + Write-Log "URL: $bootstrapperUrl" + + $ProgressPreference = 'SilentlyContinue' + + Invoke-WebRequest ` + -Uri $bootstrapperUrl ` + -OutFile $vsBootstrapper ` + -UseBasicParsing + + if (-not (Test-Path $vsBootstrapper)) { + throw "Visual Studio bootstrapper was not downloaded: $vsBootstrapper" + } + + $fileSize = (Get-Item $vsBootstrapper).Length + Write-Log "Bootstrapper downloaded to: $vsBootstrapper" + Write-Log "Bootstrapper size: $fileSize bytes" + + if ($fileSize -lt 500000) { + throw "Downloaded Visual Studio bootstrapper looks too small/corrupt: $fileSize bytes" + } + + Push-Location $env:TEMP + try { + $args = @( + '--wait', + '--add', 'Microsoft.VisualStudio.Workload.NativeDesktop', + '--add', 'Microsoft.VisualStudio.Workload.ManagedDesktop', + '--includeRecommended', + '--quiet', + '--norestart' + ) + + Write-Log "Running: $vsBootstrapper $($args -join ' ')" + + $p = Start-Process ` + -FilePath $vsBootstrapper ` + -ArgumentList $args ` + -WorkingDirectory $env:TEMP ` + -Wait ` + -PassThru + + Write-Log "Visual Studio bootstrapper exit code: $($p.ExitCode)" + } + finally { + Pop-Location + } + + Remove-Item $vsBootstrapper -Force -ErrorAction SilentlyContinue + + if ($p.ExitCode -eq 0 -or $p.ExitCode -eq 3010 -or $p.ExitCode -eq 1641) { + Write-Log "Visual Studio 2026 Enterprise installed successfully." + return + } + + Throw-WithVsLogs -Message "Visual Studio install failed." -ExitCode $p.ExitCode + + metadata: + description: Install Visual Studio 2026 Enterprise with C++ and C# workloads + securityContext: elevated