Skip to content

Instantly share code, notes, and snippets.

@taskie
Created April 13, 2026 07:02
Show Gist options
  • Select an option

  • Save taskie/a46fc6e2e351e223eafca7e64c87403b to your computer and use it in GitHub Desktop.

Select an option

Save taskie/a46fc6e2e351e223eafca7e64c87403b to your computer and use it in GitHub Desktop.

WSL / ターミナルから Windows 通知を送る方法

WSL やターミナル環境から Windows のネイティブ通知・タスクバー連携を行う方法をまとめる。


1. PowerShell ワンライナー(Toast 通知)

WSL から powershell.exe を呼び出し、WinRT の Toast Notification API を使う方法。Windows のアクションセンターにバナーが表示される。

最小例

powershell.exe -NoProfile -Command "
  [Windows.UI.Notifications.ToastNotificationManager,
   Windows.UI.Notifications,
   ContentType = WindowsRuntime] | Out-Null;
  \$xml = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent(1);
  \$nodes = \$xml.GetElementsByTagName('text');
  \$nodes.Item(0).AppendChild(\$xml.CreateTextNode('Title'));
  \$nodes.Item(1).AppendChild(\$xml.CreateTextNode('Body'));
  \$toast = [Windows.UI.Notifications.ToastNotification]::new(\$xml);
  [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('WSL').Show(\$toast)
"

解説

処理 説明
ContentType = WindowsRuntime WinRT 型を PowerShell セッションにロードする指定
GetTemplateContent(1) ToastText02(タイトル+本文)テンプレートの XML を取得。0ToastText01(本文のみ)
CreateToastNotifier('WSL') 引数は AppUserModelID(AUMID)。通知のグループ化に使われる

シェル関数化

win_notify() {
  local title="${1:-Notification}"
  local body="${2:-}"
  powershell.exe -NoProfile -Command "
    [Windows.UI.Notifications.ToastNotificationManager,
     Windows.UI.Notifications,
     ContentType = WindowsRuntime] | Out-Null;
    \$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent(1);
    \$n = \$t.GetElementsByTagName('text');
    \$n.Item(0).AppendChild(\$t.CreateTextNode('$title'));
    \$n.Item(1).AppendChild(\$t.CreateTextNode('$body'));
    [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('WSL').Show(
      [Windows.UI.Notifications.ToastNotification]::new(\$t))
  "
}

# 使用例
make build && win_notify "Build Complete" "All tests passed" \
           || win_notify "Build Failed" "Check output for errors"

注意点

  • powershell.exe のプロセス起動コストがあるため高頻度の呼び出しには不向き
  • 引数にシングルクォートや特殊文字を含む場合はエスケープが必要

2. C#(.NET + WinRT)

Windows 側でビルドする .NET コンソールアプリケーション。イベントハンドリングやカスタム XML による高度な通知が可能。

プロジェクト作成

dotnet new console -n WslToast
cd WslToast

WslToast.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>

-windows10.0.17763.0 は TFM の Windows 固有サフィックスで、WinRT API(Windows.UI.Notifications)への直接アクセスを有効にする。内部的には CsWinRT が .NET と WinRT の間を橋渡しする。

Program.cs — 基本

using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;

var title = args.Length > 0 ? args[0] : "Notification";
var body  = args.Length > 1 ? args[1] : "";
var appId = args.Length > 2 ? args[2] : "WSL";

var xml = ToastNotificationManager.GetTemplateContent(
    ToastTemplateType.ToastText02);

var textNodes = xml.GetElementsByTagName("text");
textNodes[0].AppendChild(xml.CreateTextNode(title));
textNodes[1].AppendChild(xml.CreateTextNode(body));

var toast = new ToastNotification(xml);

toast.Activated += (_, _) => Console.WriteLine("Toast clicked");
toast.Dismissed += (_, e) => Console.WriteLine($"Dismissed: {e.Reason}");
toast.Failed    += (_, e) => Console.WriteLine($"Failed: {e.ErrorCode}");

ToastNotificationManager
    .CreateToastNotifier(appId)
    .Show(toast);

Thread.Sleep(500); // イベント受信用。不要なら削除可

Program.cs — ボタン付きインタラクティブ通知

using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;

var xmlString = @"
<toast activationType='foreground'>
  <visual>
    <binding template='ToastGeneric'>
      <text>Deploy to production?</text>
      <text>main branch, commit abc1234</text>
    </binding>
  </visual>
  <actions>
    <action content='Deploy' activationType='foreground' arguments='deploy'/>
    <action content='Cancel' activationType='foreground' arguments='cancel'/>
  </actions>
</toast>";

var xml = new XmlDocument();
xml.LoadXml(xmlString);

var toast = new ToastNotification(xml);
toast.Activated += (_, args) =>
{
    if (args is ToastActivatedEventArgs a)
        Console.WriteLine($"Action: {a.Arguments}");
};

ToastNotificationManager
    .CreateToastNotifier("WSL")
    .Show(toast);

Thread.Sleep(30_000); // ユーザー操作待ち

WSL からの呼び出し

/mnt/c/path/to/WslToast.exe "Build Complete" "All tests passed"

3. OSC エスケープシーケンス(Windows Terminal)

追加の依存なしにターミナルから直接使える。Windows Terminal が OSC シーケンスを解釈して Windows API を呼び出す仕組み。

OSC 9;4 — タスクバープログレス

タスクバーアイコン上にプログレスバーを表示する。内部的に ITaskbarList3::SetProgressState / SetProgressValue が呼ばれる。

フォーマット: ESC ] 9 ; 4 ; <state> ; <value> ST

state 表示 対応する COM 定数
0 非表示(クリア) TBPF_NOPROGRESS
1 通常(緑) TBPF_NORMAL
2 エラー(赤) TBPF_ERROR
3 警告(黄) TBPF_PAUSED
4 不確定(パルス) TBPF_INDETERMINATE
# 進捗 50%
printf '\e]9;4;1;50\e\\'

# 完了
printf '\e]9;4;1;100\e\\'

# エラー表示
printf '\e]9;4;2;100\e\\'

# クリア
printf '\e]9;4;0;0\e\\'

# 不確定(所要時間不明の処理向き)
printf '\e]9;4;4;0\e\\'

OSC 9;9 — タスクバー点滅通知

Windows Terminal が非フォーカス時にタスクバーアイコンを点滅させる。アクションセンターには表示されない。

printf '\e]9;9;"Build finished"\e\\'

実用シェル関数

notify() {
  printf '\e]9;9;"%s"\e\\' "${1:-Done}"
}

progress() {
  local state="${1:-1}" pct="${2:-0}"
  printf '\e]9;4;%d;%d\e\\' "$state" "$pct"
}

progress_clear() {
  printf '\e]9;4;0;0\e\\'
}

done_notify() {
  local rc=$?
  if [ $rc -eq 0 ]; then
    progress 1 100
    notify "Success"
  else
    progress 2 100
    notify "Failed (exit $rc)"
  fi
  (sleep 3 && progress_clear) &
}

# 使用例
cargo build --release ; done_notify

ビルドスクリプトでの進捗表示

build_with_progress() {
  local total=5 current=0
  for step in configure compile link test install; do
    current=$((current + 1))
    pct=$((current * 100 / total))
    printf '\e]9;4;1;%d\e\\' "$pct"
    echo "[$pct%] $step..."
    # 実際のビルド処理
  done
  printf '\e]9;4;0;0\e\\'
}

tmux 経由

tmux 内では OSC シーケンスが外側のターミナルに届かないため、パススルーが必要。

printf '\ePtmux;\e\e]9;4;1;50\e\e\\\e\\'

複数タブ・ペイン

Windows Terminal は全タブの状態を集約してタスクバーに表示する。優先順位はエラー(赤) > 通常(緑) > 不確定(パルス)の順。


方法の比較

PowerShell C# (.NET) OSC シーケンス
通知の種類 Toast(アクションセンター) Toast(アクションセンター) タスクバー点滅・プログレス
追加依存 なし(WSL 標準) .NET SDK + ビルド なし(Windows Terminal のみ)
起動コスト 高(ps プロセス) 中(.NET ランタイム) なし
ボタン等の対話 可(XML カスタマイズ) 可(イベントハンドリング付き) 不可
プログレスバー 不可 ITaskbarList3 で可能 OSC 9;4 で対応
用途 手軽なワンショット通知 高度な通知アプリ ターミナル内完結の軽い通知
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment