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" -s

However, 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!