Toggle Between Light and Dark Mode in Windows using PowerShell
It's possible with a simple script!
I've recently spent a good amount of time to make my Windows OS look more pleasant.
The first thing I did for this, was to switch it to dark mode, which, in my opinion, is a lot more visually pleasing than the default light mode.
I documented how to set this up and some other tweaks in my article Windows Can be Zen Too.
However, I recently found myself working in a room with lots of natural light– and unfortunately, using dark mode, had to look back at my own reflection a lot.
Innocently I thought it would be child's play to write a little script that I can call that changes my desktop from dark to light mode and vice averse, as well as changes the 'accent' color Windows uses.
It turned out way more complicated than I imagined, and I actually had to abandon my plans to change the accent color, since that required a lot of hacky code.
In any case, just changing between light and dark mode is not too complicated and a simple PowerShell script does the job.
If you are interested to automate this as well, please find the whole script below. Just download it, and create a shortcut to the script.
param(
[Parameter(Mandatory=$false)]
[ValidateSet("Dark", "Light")]
[string]$Theme
)
$ErrorActionPreference = "Stop"
$PersonalizePath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
function Get-CurrentTheme {
$appsUseLight = (Get-ItemProperty -Path $PersonalizePath -Name "AppsUseLightTheme" -ErrorAction SilentlyContinue).AppsUseLightTheme
if ($appsUseLight -eq 0) { return "Dark" }
return "Light"
}
function Set-SystemTheme {
param([string]$Mode)
$value = if ($Mode -eq "Light") { 1 } else { 0 }
Set-ItemProperty -Path $PersonalizePath -Name "AppsUseLightTheme" -Value $value -Type DWord -Force
Set-ItemProperty -Path $PersonalizePath -Name "SystemUsesLightTheme" -Value $value -Type DWord -Force
}
function Broadcast-WMChange {
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
}
if (-not $Theme) {
$current = Get-CurrentTheme
$Theme = if ($current -eq "Dark") { "Light" } else { "Dark" }
Write-Host "Toggling from $current -> $Theme"
} else {
Write-Host "Setting theme to: $Theme"
}
Set-SystemTheme -Mode $Theme
Broadcast-WMChange
Write-Host "Done."And here is the Target for the shortcut
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy Bypass -File "[path to your]\toggle-mode.ps1"I needed to do this with a script since I use Windows Subsystem for Linux extensively, and here specifically OpenCode.
Unfortunately, the terminal emulator I'm using – Alacritty – does not automatically switch from light to dark mode when Windows does; and neither does OpenCode when Alacritty changes.
So for both of these I needed to manually change their theme every time I want to switch between light and dark mode.
In case this is of interested to you, here also the code for how to change the theme in PowerShell for Alacritty:
$alacrittyTheme = if ($Theme -eq "Dark") { "opencode-dark.toml" } else { "opencode-light.toml" }
$alacrittyPath = "$env:APPDATA\alacritty\alacritty.toml"
if (Test-Path $alacrittyPath) {
$content = Get-Content $alacrittyPath -Raw
$content = $content -replace 'alacritty-theme/themes/opencode-[^/]*\.toml', "alacritty-theme/themes/${alacrittyTheme}"
Set-Content -Path $alacrittyPath -Value $content -NoNewline
Write-Host "Set Alacritty theme to: $alacrittyTheme"
}Note I'm using two custom Alacritty themes I've created here opencode-light.toml and opencode-dark.toml - but you can use any other theme you like!
And here how to do the same for OpenCode:
#!/bin/bash
set -e
THEME="$1"
if [[ "$THEME" != "light" && "$THEME" != "dark" ]]; then
echo "Usage: toggle-mode.sh [light|dark]"
exit 1
fi
CONFIG="${HOME}/.config/opencode/tui.json"
if [[ ! -f "$CONFIG" ]]; then
echo "Error: OpenCode config not found at $CONFIG"
exit 1
fi
sed -i "s/\"theme\": \"[^\"]*\"/\"theme\": \"custom-${THEME}\"/" "$CONFIG"
echo "Set OpenCode theme to: custom-${THEME}"For OpenCode, I also use custom themes, since OpenCode has its own logic for supporting light and dark mode. Unfortunately, I did not find this to be working well with Alacritty, so the best workaround I found was to create custom themes that use the exact same colors for light and dark mode – so we don't need to worry about whether OpenCode is in light or dark mode.
For reference, here how my OpenCode light theme looks like – note it has the exact same colors for the 'light' and 'dark' theme:
{
"$schema": "https://opencode.ai/theme.json",
"name": "Custom Light",
"defs": {
"neutral": "#ffffff",
"ink": "#1a1a1a",
"primary": "#3b7dd8",
"accent": "#d68c27",
"success": "#3d9a57",
"warning": "#d68c27",
"error": "#d1383d",
"info": "#318795",
"diffAdd": "#4db380",
"diffDelete": "#f52a65",
"textWeak": "#8a8a8a",
"syntaxComment": "#8a8a8a",
"syntaxKeyword": "#d68c27",
"syntaxString": "#3d9a57",
"syntaxPrimitive": "#3b7dd8",
"syntaxVariable": "#d1383d",
"syntaxProperty": "#318795",
"syntaxType": "#b0851f",
"syntaxConstant": "#d68c27",
"syntaxOperator": "#318795",
"syntaxPunctuation": "#1a1a1a",
"syntaxObject": "#d1383d",
"markdownHeading": "#d68c27",
"markdownText": "#1a1a1a",
"markdownLink": "#3b7dd8",
"markdownLinkText": "#318795",
"markdownCode": "#3d9a57",
"markdownBlockQuote": "#b0851f",
"markdownEmph": "#b0851f",
"markdownStrong": "#d68c27",
"markdownHorizontalRule": "#8a8a8a",
"markdownListItem": "#3b7dd8",
"markdownListEnumeration": "#318795",
"markdownImage": "#3b7dd8",
"markdownImageText": "#318795",
"markdownCodeBlock": "#1a1a1a"
},
"theme": {
"primary": {
"dark": "primary",
"light": "primary"
},
"secondary": {
"dark": "accent",
"light": "accent"
},
"accent": {
"dark": "accent",
"light": "accent"
},
"error": {
"dark": "error",
"light": "error"
},
"warning": {
"dark": "warning",
"light": "warning"
},
"success": {
"dark": "success",
"light": "success"
},
"info": {
"dark": "info",
"light": "info"
},
"text": {
"dark": "neutral",
"light": "ink"
},
"textMuted": {
"dark": "textWeak",
"light": "textWeak"
},
"background": {
"dark": "neutral",
"light": "neutral"
},
"backgroundPanel": {
"dark": "neutral",
"light": "neutral"
},
"backgroundElement": {
"dark": "neutral",
"light": "neutral"
},
"border": {
"dark": "neutral",
"light": "neutral"
},
"borderActive": {
"dark": "textWeak",
"light": "textWeak"
},
"borderSubtle": {
"dark": "neutral",
"light": "neutral"
},
"diffAdded": {
"dark": "diffAdd",
"light": "diffAdd"
},
"diffRemoved": {
"dark": "diffDelete",
"light": "diffDelete"
},
"diffContext": {
"dark": "textWeak",
"light": "textWeak"
},
"diffHunkHeader": {
"dark": "textWeak",
"light": "textWeak"
},
"diffHighlightAdded": {
"dark": "diffAdd",
"light": "diffAdd"
},
"diffHighlightRemoved": {
"dark": "diffDelete",
"light": "diffDelete"
},
"diffAddedBg": {
"dark": "neutral",
"light": "neutral"
},
"diffRemovedBg": {
"dark": "neutral",
"light": "neutral"
},
"diffContextBg": {
"dark": "neutral",
"light": "neutral"
},
"diffLineNumber": {
"dark": "textWeak",
"light": "textWeak"
},
"diffAddedLineNumberBg": {
"dark": "neutral",
"light": "neutral"
},
"diffRemovedLineNumberBg": {
"dark": "neutral",
"light": "neutral"
},
"markdownText": {
"dark": "markdownText",
"light": "markdownText"
},
"markdownHeading": {
"dark": "markdownHeading",
"light": "markdownHeading"
},
"markdownLink": {
"dark": "markdownLink",
"light": "markdownLink"
},
"markdownLinkText": {
"dark": "markdownLinkText",
"light": "markdownLinkText"
},
"markdownCode": {
"dark": "markdownCode",
"light": "markdownCode"
},
"markdownBlockQuote": {
"dark": "markdownBlockQuote",
"light": "markdownBlockQuote"
},
"markdownEmph": {
"dark": "markdownEmph",
"light": "markdownEmph"
},
"markdownStrong": {
"dark": "markdownStrong",
"light": "markdownStrong"
},
"markdownHorizontalRule": {
"dark": "markdownHorizontalRule",
"light": "markdownHorizontalRule"
},
"markdownListItem": {
"dark": "markdownListItem",
"light": "markdownListItem"
},
"markdownListEnumeration": {
"dark": "markdownListEnumeration",
"light": "markdownListEnumeration"
},
"markdownImage": {
"dark": "markdownImage",
"light": "markdownImage"
},
"markdownImageText": {
"dark": "markdownImageText",
"light": "markdownImageText"
},
"markdownCodeBlock": {
"dark": "markdownCodeBlock",
"light": "markdownCodeBlock"
},
"syntaxComment": {
"dark": "syntaxComment",
"light": "syntaxComment"
},
"syntaxKeyword": {
"dark": "syntaxKeyword",
"light": "syntaxKeyword"
},
"syntaxFunction": {
"dark": "syntaxKeyword",
"light": "syntaxKeyword"
},
"syntaxVariable": {
"dark": "syntaxVariable",
"light": "syntaxVariable"
},
"syntaxString": {
"dark": "syntaxString",
"light": "syntaxString"
},
"syntaxNumber": {
"dark": "syntaxConstant",
"light": "syntaxConstant"
},
"syntaxType": {
"dark": "syntaxType",
"light": "syntaxType"
},
"syntaxOperator": {
"dark": "syntaxOperator",
"light": "syntaxOperator"
},
"syntaxPunctuation": {
"dark": "syntaxPunctuation",
"light": "syntaxPunctuation"
}
}
}As mentioned, I wasn't quite able to get the accent color change in Windows working.
What I did find out was that there is a very useful application called WinPaletter that makes it somewhat doable to change the accent color. I even found it has a CLI that can be used to apply themes automatically:
WinPaletter.exe -a "C:\Users\You\MyTheme.wpth" -sHowever, WinPaletter does all different kinds of scary things with the Windows config, so I got cold feet and thought I see if I live without an automatically changing accent color.
In any case, if anyone has found a reliable way to toggle light/dark mode through a script while changing the Windows colors, please get in touch!