Windows10 のテーマを変更する PowerShell Script


作成の背景

壁紙をスライドショー形式で設定しているのだが、時間帯によって参照フォルダーを変えたいというのが目的。

レジストリーにフォルダー・パスが直接記入されているだろうから、cmd.exe をタスク・スケジューラーから叩くだけで簡単に実現できるかと思いきや、どうも複雑な指定がされているみたいで、結局以下のスクリプトでテーマをまるごと切り替える方法を採ることとした。

コード

ThemeChanger.ps1
<#  Theme Changer for Windows 10 by Jutha DDA #>

# .theme ファイルのパスを指定
    [String]$pathTheme1 = "C:\Users\johndoe\AppData\Local\Microsoft\Windows\Themes\foo.theme" 
    [String]$pathTheme2 = "C:\Users\johndoe\AppData\Local\Microsoft\Windows\Themes\bar.theme"
    [String]$pathTheme3 = "C:\Users\johndoe\AppData\Local\Microsoft\Windows\Themes\Roamed.theme"
# "HH:mm" 形式でテーマを変更する時刻を指定( 1<2<3 となるように指定すること)
    [String]$timeStartTheme1 = "00:00" 
    [String]$timeStartTheme2 = "15:00"
    [String]$timeStartTheme3 = "21:30"

# $timeStartThemesX を Get-Date に渡すために時と分に分解
$hour1   = [Int]($timeStartTheme1 -replace ":.*", "")
$minute1 = [Int]($timeStartTheme1 -replace ".*:", "")
$hour2   = [Int]($timeStartTheme2 -replace ":.*", "")
$minute2 = [Int]($timeStartTheme2 -replace ".*:", "")
$hour3   = [Int]($timeStartTheme3 -replace ":.*", "")
$minute3 = [Int]($timeStartTheme3 -replace ".*:", "")

# すでに SystemSetting ウィンドウが開いている場合、ページが遷移するため確認を行う。
$killSystemSettings = $true # SystemSettings が開いていない場合は、実行後ウィンドウを閉じる。
if ( (Get-Process | Where-Object { $_.ProcessName -eq "SystemSettings" }) ) {
    Read-Host "テーマ変更スクリプトを続けるには、Enter を押してください(「設定」ウィンドウのページが「テーマ」に切り替わります)。"
    $killSystemSettings = $false # SystemSettings が開いている場合は、実行後ウィンドウを閉じない
}

# 時刻に応じてテーマを切り替える。
if (
    ( ( Get-Date ) -ge ( Get-Date -Hour $hour1 -Minute $minute1 ) ) -and
    ( ( Get-Date ) -lt ( Get-Date -Hour $hour2 -Minute $minute2 ) )
) {
    Start-Process $pathTheme1 -Wait
} elseif (
    ( ( Get-Date ) -ge ( Get-Date -Hour $hour2 -Minute $minute2 ) ) -and
    ( ( Get-Date ) -lt ( Get-Date -Hour $hour3 -Minute $minute3 ) )
) {
    Start-Process $pathTheme2 -Wait
} else {
    Start-Process $pathTheme3 -Wait
}

# SystemSettings が開くので閉じる(最初から開いていた場合は閉じない)。
if ( $killSystemSettings ) {
    Get-Process | Where-Object { $_.ProcessName -eq "SystemSettings" } | ForEach-Object { $_.Kill() }
    # SystemSetting プロセスが終了する前に、数秒ウィンドウが表示される場合がある。
}

Start-ProcessInvoke-Command に変えても動く。

タスクスケジューラの設定

トリガー

  1. 「スケジュールに従う」>「毎日」を選択。
  2. スクリプトの $timeStartTheme1 と同じ開始時刻を指定。
  3. $timeStartTheme2$timeStartTheme3 についても、同様にトリガーを追加。

操作

  1. 「プログラムの開始」を選択。
  2. 「プログラム/スクリプト」に PowerShell のパス(C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe)を入力。
  3. 「引数の追加に」-Command ".\WallpaperChanger.ps1" と入力。
  4. 「開始」にスクリプト・ファイルのパス(例:C:\User\johndoe\hoge fuga\piyo)を入力(引用符 "" も半角スペース等のエスケープ ` も不要)。

設定

  1. 「スケジュールされた時刻にタスクを開始できなかった場合、すぐにタスクを実行する」にチェックを入れる。

改善したい点

  • 「設定」アプリ(SystemSettings.exe)の起動画面がどうしても表示されてしまうのを解消したい( 実行ファイルを指定してプロセスを起動していないためか、-WindowStyle Hidden は効果がなかった。)
  • SystemSettings.exe の起動待ちを for 構文で実装しているのが、あまりスマートに思えないので、他の方法で起動を検知したい。使えないと勘違いしていた Start-Process -Wait が使えることが判明したため、修正。
  • 「設定」アプリで他のページを開いていた場合、ページ遷移が発生してしまう問題もあるので、そもそも SystemSettings.exe を起動させないで、テーマを切り替えたい(さらにそもそもをいえば、「コントロールパネル」みたいに複数起動できないのをなんとかしてほしいと思うのだが)。

以上です。