notebook

都内でWEB系エンジニアやってます。

WSLからWindowsへ通知を送る

GitHub CLIを使ってターミナルでGitHub Actionsを操作する - GitHubブログ

github.blog

GitHubのCLIにworkflow,runが増えた記事を見て

記事の中でnotify-sendを用いてworkflowが終わったらデスクトップ通知するみたいなのを見た

そういえばworkflow以外にもローカルで実行している時間のかかる処理を複数回実行するときなど

実行して数分他の作業して確認してまだだったからもう少し他の作業して…みたいな気の散る状態が結構あったのでデスクトップ通知があると効率的な場合もありそうだなということで

WSL2でもデスクトップ通知したいと思い調べてみた

ちなみにIssueは Feature Request: Desktop Notifications · Issue #2466 · microsoft/WSL

github.com

いくつか方法があるようだがPowershellでできるようなので今回はその方法を試してみた

スクリプトを置いてWSLからたたくだけでOK

powershellスクリプトは初めてだったので次の記事のスクリプト部分を丸々拝借した

WSLからWindowsに通知 - uochan

scrapbox.io

  • c:/Users/hoge/Desktop/notify.ps1
param(
    [string]$Prompt = 'message',
    [string]$Title  = 'notification',
    $CallBack = ''
)

Add-Type -AssemblyName System.Windows.Forms, System.Drawing

function Show-NotifyIcon {
    param(
        [string]$Prompt = 'm',
        [string]$Title  = 'n',
        [scriptblock]$CallBack = {}
    )

    [Windows.Forms.NotifyIcon]$notifyIcon =
        New-Object -TypeName Windows.Forms.NotifyIcon -Property @{
            BalloonTipIcon  = [Windows.Forms.ToolTipIcon]::Info
            BalloonTipText  = $Prompt
            BalloonTipTitle = $Title
            Icon    = [Drawing.SystemIcons]::Information
            Text    = $Title
            Visible = $true
        }

    # イベント定義
    $notifyIcon.add_BalloonTipClicked( $CallBack )

    [int]$timeout = 3 # sec

    [DateTimeOffset]$finishTime = 
        [DateTimeOffset]::UtcNow.AddSeconds( $timeout )

    $notifyIcon.ShowBalloonTip( $timeout )

    # そのままだとイベントが走らない&すぐに消えてしまうので適当wait
    while ( [DateTimeOffset]::UtcNow -lt $finishTime ) {
        Start-Sleep -Milliseconds 1
    }
    $notifyIcon.Dispose()
}

$parameters = $MyInvocation.BoundParameters
$parameters.CallBack = [scriptblock]::Create( $CallBack )
Show-NotifyIcon @parameters
  • たたく
/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -Sta -NoProfile -WindowStyle Hidden -ExecutionPolicy RemoteSigned -File c:/Users/hoge/Desktop/notify.ps1 "メッセージ" "タイトル"

f:id:swfz:20210519195813p:plain

無事デスクトップ通知がきた

Powershell実行時のオプションなどのメモ

about_PowerShell_exe - PowerShell | Microsoft Docs

docs.microsoft.com

-Sta

シングルスレッドアパートメントを使用してPowerShellを起動する

-NoProfile

PowerShellプロファイルを読み込みまない

-WindowStyle

セッションのウィンドウ スタイルを設定します。 使用できる値は、Normal、Minimized、Maximized、Hiddenです

-ExecutionPolicy

現在のセッションの既定の実行ポリシーを設定する

一時的なポリシー指定

ポリシーの内容に関しては下記

about_Execution_Policies - PowerShell | Microsoft Docs

docs.microsoft.com

この辺正直あまり良くわかっていない

WSL側でコマンドを用意する

実行コマンドをラップして成功失敗まで判断して通知できるようにしてみた

#!/bin/bash

_usage(){
cat << EOS
usage:
  ./notify command [option...]

script that wraps a command and changes the message depending on the exit code

require environment
  POWERSHELL_EXE   path of powershell.exe as seen from wsl
    e.g.) /mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe
  NOTIFY_PS1       path of nitofy.ps1(notification script) as seen from Windows
    e.g.) c:/Users/hoge/Desktop/notify.ps1
EOS
  exit 1
}


if [ -z ${POWERSHELL_EXE} ]; then
  echo 'require environment variable POWERSHELL_EXE that contains powershell.exe path.'
  _usage
fi

if [ -z ${NOTIFY_PS1} ]; then
  echo 'require environment variable NOTIFY_PS1 that contains notify.ps2 path.'
  _usage
fi

if [ -z "$*" ]; then
  _usage
fi

$*

exit_code=$?

if [ ${exit_code} -eq 0 ]; then
  result='Success'
else
  result='Failed'
fi

${POWERSHELL_EXE} -Sta -NoProfile -WindowStyle Hidden -ExecutionPolicy RemoteSigned -File ${NOTIFY_PS1} "$*" "${result}"

上記スクリプトをPATHの通ったディレクトリに配置し実行してみる

notify ls -al
  • コマンド成功時

f:id:swfz:20210519195819p:plain

  • コマンド失敗時

f:id:swfz:20210519195825p:plain

うまく行った

Powershellに馴染みがないので微妙だが時間取れたらアイコンを切り替えてみたいなと思っている

蛇足

Feature Request: Desktop Notifications · Issue #2466 · microsoft/WSL

github.com

上記issueのコメントのようにtoastをインストールしても良さそう

やってみようと思ったが次のようにいわれてしまったのでいったんやめた

Install-Module -Name BurntToast
続行するには NuGet プロバイダーが必要です
PowerShellGet で NuGet ベースのリポジトリを操作するには、'2.8.5.201' 以降のバージョンの NuGet プロバイダーが必要です。NuGet プロバイダーは 'C:\Program
Files\PackageManagement\ProviderAssemblies' または 'C:\Users\sawafuji_yuya\AppData\Local\PackageManagement\ProviderAssemblies' に配置する必要があります。'Install-PackageProvider -Name NuGet
-MinimumVersion 2.8.5.201 -Force' を実行して NuGet プロバイダーをインストールすることもできます。今すぐ PowerShellGet で NuGet プロバイダーをインストールしてインポートしますか?
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"):
信頼されていないリポジトリ
信頼されていないリポジトリからモジュールをインストールしようとしています。このリポジトリを信頼する場合は、Set-PSRepository コマンドレットを実行して、リポジトリの InstallationPolicy
の値を変更してください。'PSGallery' からモジュールをインストールしますか?
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定値は "N"):
警告: パッケージ (BurntToast) のインストールがユーザーによって拒否されました。