OpenSSH経由でシステムクリップボードへテキストをコピー

前回までで、WindowsにOpenSSH経由でログインできるようになった。そしてその状態でGUIアプリケーションを起動できるようにもした。全ての方がこの機能を必要としているわけではないのだが、こうした仕組みをPowerShellスクリプトを使って実現できることは知っておいて損はない。

そして今度は、OpenSSH経由でシステムクリップボードへコピーしたい。例えば、テキストファイルやテキストデータをOpenSSH経由でWindowsへリモートログインして直接システムクリップボードにコピーしたい、といった用途だ。

OpenSSH経由でWindowsへリモートログインできるということは、OpenSSH経由でコマンドを実行して一発でシステムクリップボードへテキストデータをコピーできるようになることを意味している(と、期待している)。LinuxやMacからWindowsのシステムクリップボードへコピーできると、なかなか便利だ。

この機能はAppleであれば「ユニバーサルクリップボード」という機能ですでに実現されている。、テキストデータ以外のデータも汎用的にデバイスを超えてコピー&ペーストできるようになっている。今回は、PowerShellを使って似たようなことができるようにWindowsでも仕組みを作ってみよう。

基本となる考え方

システムクリップボードへのコピーは、clip.exeコマンドを使うことで実現できる。パイプライン経由でclip.exeに流し込めばよい。しかし、OpenSSH経由でリモートログインした状態では、clip.exeを実行してもシステムクリップボードへのコピーは行われないことは前回確認した通りだ。

これは、OpenSSH経由でリモートログインしている状態からGUIアプリケーションを起動するのと同じ要領で解決できる。clip.exeでシステムクリップボードへのコピーが可能な状態でPowerShellスクリプトを実行しておき、これにシステムクリップボードへのコピーを依頼するかたちで実現することを考えるわけだ。

やり方は前回とほとんど同じだ。目の前のPCでログオンした状態でも、OpenSSH経由でリモートログインした状態でも、ファイルシステムとしては同じものにアクセスすることができる。ファイルを使ってOpenSSHでリモートログインした状態から、PowerShellスクリプトへシステムクリップボードへのコピーを依頼すればよいのだ。

システムクリップボードへコピーするPowerShellスクリプト

では、GUIアプリケーションを起動するときに作成したスクリプトをベースに、システムクリップボードへコピーするPowerShellスクリプトを作成してみよう。ここでは次のようなPowerShellスクリプトを用意した。

winclipserver.ps1

#!/usr/bin/env pwsh

#========================================================================
# 特定のファイルに書き込まれたテキストをシステムクリップボードにコピーする
# 簡易サーバ
#========================================================================

#========================================================================
# テキストが書き込まれるファイル
#========================================================================
$clipbrdFilePath = "${HOME}/.wincmdserver_clip"

#========================================================================
# ファイルをチェックするインターバル時間[秒]
#========================================================================
$fileCheckInterval = 1.0

#========================================================================
# サーバのプロセスIDを書き込むファイル
#========================================================================
$pidFilePath = "${HOME}/.winclipserver_pid"

#========================================================================
# サーバのプロセスIDをファイルへ記録
#========================================================================
Write-Output $PID > $pidFilePath

#========================================================================
# テキストが書き込まれるファイルを初期化
#========================================================================
Write-Output $null > $clipbrdFilePath

#========================================================================
# テキストが書き込まれるファイルを監視し、テキストが書き込まれた場合に、
# テキストをシステムクリップボートへコピーしてからファイルをクリアする。
#========================================================================
while ($true) {
    # テキストファイルが存在し、かつ、中身があるときにシステムクリップ
    # ボードへコピーする
    if (Test-Path "$clipbrdFilePath") {

        if (0 -lt (Get-ChildItem "$clipbrdFilePath").Length) {

            # システムクリップボードへテキストをコピー
            cat "$clipbrdFilePath" | clip

            # ログ出力
            $timestamp = Get-Date -format "yyyy/MM/dd HH:mm:ss"
            $timestamp + " - copied to system clipboard"

            # ファイルの中身をクリア
            Clear-Content "$clipbrdFilePath"
        }
    }

    # 次のチェックまで指定秒間待機
    Start-Sleep $fileCheckInterval
}

スクリプトの仕組みは簡単だ。while ($true)とStart-Sleep 1で1秒ごとにぐるぐると処理を繰り返しているだけで、特定のファイルにテキストが書き込まれていればシステムクリップボードへコピーしてからファイルの中身を削除する、という処理を行っている。

つまり、遠隔からOpenSSH経由でリモートログインして、特定のファイル(今回は${HOME}/.wincmdserver_clip)へテキストを書き込めば、それが最長でも1秒後にはシステムクリップボードへコピーされる、ということになる。

動作確認を行う

では動作確認を行おう。まず、作成したPowerShellスクリプトを実行する。while ($true)で処理が繰り返されているので、PowerShellスクリプトはこのまま動き続ける。

  • winclipserver.ps1を実行

    winclipserver.ps1を実行

winclipserver.ps1を実行したのとは別のホストからwinclipserver.ps1を実行したホストに対して、次のようなsshを実行する。

別のホストから実行するsshコマンドのサンプル

ssh ホスト名またはIPアドレス 'echo "メッセージ" > ${HOME}/.wincmdserver_clip'

実行すると次のようになる。エラーが出ているが、これは使用しているPowerShellの実験的機能が原因になっているだけなので、無視してもらって大丈夫だ。

  • 実行サンプル

    実行サンプル

winclipserver.ps1にはシステムクリップボードへのコピーを行ったことを報告するログが出力される。

  • winclipserver.ps1におけるログ出力

    winclipserver.ps1におけるログ出力

メモ帳を起動して「Ctrl」+「V」などで貼り付けを行うと、ほかのホストから送り込んできたテキストが貼り付けられることを確認できる。

  • sshで送られてきたテキストを貼り付けできることを確認

    sshで送られてきたテキストを貼り付けできることを確認

もう一度同じように操作してみよう。次のようにWindows以外のホスト、ここではMacからWindowsのシステムクリップボードに対してテキストのコピーが行われていることを確認できる。

  • Macでsshコマンドを実行

    Macでsshコマンドを実行

  • Windowsで動いているwinclipserver.ps1でログ出力

    Windowsで動いているwinclipserver.ps1でログ出力

  • Macから送られてきたテキストをシステムクリックボード経由で貼り付け

    Macから送られてきたテキストをシステムクリックボード経由で貼り付け

まずはPowerShellスクリプトを作って動作を確認

これで、システムクリップボードにコピーする仕組みを作ることができた。アイデアも実装もシンプルなものだが、実用的な機能だ。

PowerShellを使う最大の利点は、やはりこの手軽さにある。実行速度や消費リソースを気にするとか、もっと大量のコネクションを受け付けたいとか、そういった場合にはC++やC#のような別のプログラミング言語を使うことになると思うが、自分の環境で手軽に動いてくれればよい、くらいの用途であれば、PowerShellスクリプトで十分だろう。PowerShellスクリプト自体が強力なプログラミング言語であり、さまざまな処理を手軽に行うことができるのだ。