1
2

More than 1 year has passed since last update.

窓辺通知 over SSH with WSL & Powershell

Last updated at Posted at 2022-05-24

既出じゃないことを祈る.
リハビリ更新です.

TL;DR

  • リモートのLinuxサーバーで作業終わったら,Windowsでアラームしたい.
  • どうも Powershellの New-BurntToastNotification というものをつかえばいいらしい.
  • WSLからPowershell叩けばいいよね.

image.png

必要なもの

  • Windows(検証: Windows 11 21H2 220000.652)
    • Powershell version 5(以上?)(検証: 5.1.22000.652)
    • WSL(検証: Ubuntu 20.04.4 LTS/WSL2 Kernel 5.10.102.1)
      • ssh, netcat, sh
  • Linux鯖(検証: Ubuntu 18.04 LTS)
    • sshd, netcat, sh

New-BurntToastNotificationとやらについて

TL;DR

# Policy変えて 
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
# インスコ
Install-Module -Name BurntToast
# 一応(?)いんぽーと
Import-Module BurntToast
# 実行テスト
New-BurntToastNotification -Text hoge
# -Sound Call[|2-10], -Sound Alarm[|2-10]で着信やアラーム音できる.
New-BurntToastNotification -Text piyo -Sound Alarm
# Logoアイコンもいける
New-BurntToastNotification -Text hoge -AppLogo C:\path\to\logo.png

WSLからテスト

powershell.exe "New-BurntToastNotification -Text fuga"

テスト

nc越し

$ powershell.exe "New-BurntToastNotification $(nc -w1 -lvp47123 -s"127.0.0.1" >& /dev/null)" &
$ lsof -i:47123 # check listening
$ echo "-Text fuga" | nc 192.0.2.1 47123 -w1 # failed(no localhost address)
$ echo "-Text hoge" | nc localhost 47123 # success

ssh越し

user@local:~$ powershell.exe "New-BurntToastNotification $(nc -w1 -lvp47123 -s"127.0.0.1" >& /dev/null)" &
user@local:~$ ssh -R 47123:127.0.0.1:47123 remote
user@remote:~$ echo "-Text hoge" | nc localhost 47123

シェルスクリプト書く.

source below_shellscript.sh
# 47123ポートでやりとり
export WSL_NOTIF_PORT="47123"

# WSLだったら....
if [[ -v WSL_DISTRO_NAME ]];then
# WSL通知待ちを定義
_waitWslNotification() {
  WSL_NOTIF_LOGO_PATH=" "
  # lsb-release呼んで Ubuntuなら,WSLのdotfilesの中に突っ込んであるubuntu.pngを抜く.
  # ほかの奴はTux君(linux.png)表示.
  source /etc/lsb-release
  case "$DISTRIB_ID" in
    "Ubuntu") logo="-AppLogo $(wslpath -w "$HOME/.zsh/assets/logos/ubuntu.png")" ;;
    *) logo="-AppLogo $(wslpath -w "$HOME/.zsh/assets/logos/linux.png")" ;;
  esac
  # 
  while true; do
    recv="$(nc -w1 -lvp"$WSL_NOTIF_PORT" -s"127.0.0.1")"
  # 受信データあれば通知! 
    [[ "$recv" != "" ]] && powershell.exe "New-BurntToastNotification $logo $recv"
  done
}
# 47123ポート使ってなかったら,実行する.
if ! (lsof -i:"$WSL_NOTIF_PORT" > /dev/null 2>&1);then
# &!で裏で実行かつシェル閉じても実行し続けるようにしとく(デーモンでよくないか?)
_waitWslNotification &! >&/dev/null
fi
fi
# nc投げるだけのWrapper関数
## help text
_wslnotify_help(){
cat << USAGE
Usage: wslnotify [-a AlarmNumber(1-10) | -c CallNumber(1-10)] [-t text]

Options:
 -a | --alarm [number]: ring alarm
 -c | --call  [number]: ring alarm
 -t | --text  [text]: notify text
 -v | --verbose: verbose mode
 -h | --help: help text(this)
USAGE
}

## main
wslnotify() {
  text=""
  sound=""
  verbose=1
  # check args
  OPTS=$(getopt -o hva:c:t: -l help,verbose,alarm:,call:,text: -- "$@")
  p=$?
  if  ! $(return $p) || [[ $# -eq 0 ]]; then
    _wslnotify_help
    return 1
  fi
  # rotate args
  eval set -- "$OPTS"
  while true; do
    case $1 in
      -h | --help)
        _wslnotify_help
        return 0
        ;;
      -v | --verbose)
        verbose=0
        shift
      ;;

      -a | --alarm)
        if [[ $2 -lt 1 ]] || [[ $2 -gt 10 ]];then
          echo "Error: Invalid Alarm Number: $2"
          return 1
        fi
        if [[ $2 -lt 1 ]] || [[ $2 -gt 10 ]];then
          echo "Error: Invalid Call Number: $2"
          return 1
        fi
        sound="-Sound Alarm$2"
        [[ $2 -eq 1 ]] && sound="-Sound Alarm"
        shift 2
        ;;
      -c | --call)
        sound="-Sound Call$2"
        [[ $2 -eq 1 ]] && sound="-Sound Call"
        shift 2
        ;;
      -t | --text)
        text="-Text $2"
        shift 2
        ;;
      --)
        shift
        break
        ;;
      *)
        echo "Error: getopts error." >&2
        return 1
        ;;
    esac
  done
  # verbose mode
  if $(return $verbose);then
    echo "VERBOSE: Send to \"$sound $text\""
  fi
  # sending
  echo "$sound $text" | nc -w1 127.0.0.1 "$WSL_NOTIF_PORT"
}

# sshするときにプロキシ張る
alias ssh='ssh -R ${WSL_NOTIF_PORT}:localhost:${WSL_NOTIF_PORT}'

TODO:

  • Socket用意してる状態で何回もssh -R 47123:localhost::47123 していいのか?
    • Socketファイルの有る無しで挙動変えさせる? alias ssh --> function ssh()
  • ncに依存せずに,/dev/tcp/localhost/47123だっけ?,を使えないか?
  • 47123を開けっ放しにできないか?(-k使えたっけ)
  • wslnotifyじゃなくてwinotifyのほうがいいかも

End of Article

  • WSLを用いたSSH接続状態におけるクライアントWindows通知の実装した.
  • tmux上で長い処理をしてたけど,いつ終わるのかをSlackとかにWebhookで送ってたけど,よりシンプルに通知できた.
  • 今後はSlack webhookで用いてたプロセス監視スクリプトと合体し,処理が終わったら自動的に通知するようにしたりを検討する.
  • また,tmuxの子プロセスでフォアグラウンドで動くプロセスで,一定時間以上走っているものがQUITしたら自動的に通知とか,ひまがあればやってみる.
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2