ここ数回、PowerShellの新機能や2022年のPowerShellの見通しについてまとめたため話題が飛んでしまったが、今回からは連載の流れに戻ろう。

第188回までに作っていたPowerShellスクリプトは、OpenSSH経由でほかのホストからWindowsのシステムクリップボードへテキストデータを貼り付けるというものだ。

Windowsではclip.exeコマンドを使うことでクリップボードにテキストデータを貼り付けることができるのだが、OpenSSH経由でWindowsにリモートログインした状態では、clip.exeを使ってもテキストデータを貼り付けることはできない。

この問題を解決するために、clip.exeでクリップボードにテキストを貼り付けられる状態(つまり、Windowsパソコンに普通にサインインして使っている状態)でサーバを事前に実行しておくことにした。サーバがOpenSSH経由でやってくるテキストデータを監視し、データがやってきたらclip.exeを使ってシステムクリップボードに対して貼り付けを行うというものだ。こうやって事前にサーバを動作させておけば、問題解決というわけである。

そして前回、PowerShellスクリプトでそのサーバを開発した。作成したサーバのスクリプトファイル「winclipserver.ps1」は次の通りだ。

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

#========================================================================
# テキストが書き込まれるファイル
#========================================================================
$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
}

ご覧の通り、winclipserver.ps1がやっているのはすごくシンプルな処理だ。while文($true)でぐるぐる処理が回っているだけであり、「${HOME}/.wincmdserver_clip」というファイルに何らかのテキストデータが書き込まれた場合に、その中身をclip.exeコマンドでクリップボードへコピーしているだけである。

前回はこのサーバを動作させ、Windows以外のホストから1行のテキストがコピー&ペーストできることを確認した。今回は、この処理をファイルや複数行のテキストデータにまで広げてみる。

ファイルや複数行テキストデータをリモートログイン先へ送信する方法

この機能の使い道にはどんなものがあるだろうか。例えば、Macで作業しているときにあるアプリケーションに表示されているテキストを選択した際、それが自動的にWindowsで貼り付けできるようにしたいとか、Linuxで作業しているときのコマンドの出力結果を、そのまま自動的にWindowsで貼り付けるようにしたいとか、そんなケースが考えられる。

前回の実験では「echo テキスト」のような出力をWindows側へ送ったわけだが、実際には1行のテキストではなく、複数行のテキストを送るようにしたい。

実現する方法はいくつかあるが、簡単に済ませるならssh経由でWindowsにアクセスするときに、パイプを使ってデータをそのまま流し込んでしまえばいい。コマンドの実行結果を送るならば、以下のような感じだ。

コマンド | ssh WindowsホストのIPアドレス 'cat > ${HOME}/.wincmdserver_clip'

ファイルの中身をそのままリモートログイン先へ送るのであれば、次のようになる。

cat ファイル | ssh WindowsホストのIPアドレス 'cat > ${HOME}/.wincmdserver_clip'

ということで、上記のようなコマンドを実行するようなシェルスクリプト(これをPowerShellスクリプトにしてもよいのだが、ここではLinuxやMacからWindowsにコピーするケースを想定しているのでシェルスクリプトにする)を用意すればよい。まず今回は簡単に、次のような内容のシェルスクリプト「winclip」を用意してみる。

#!/bin/sh

if [ $# = "0" ]
then
        set "/dev/stdin"
fi

cat "$1" | ssh WindowsのIPアドレスまたはホスト名 'cat > ${HOME}/.wincmdserver_clip'

このシェルスクリプトは、引数があればそれをファイルパスを解釈してその中身を、引数がなければ標準入力の中身を、そのままssh経由でリモートログイン先へ送信してくれる。

シェルスクリプト側の開発は本連載の趣旨ではないので軽く触れるに留めるが、MacやLinux側のシェルスクリプトをもう少し作り込んでいくと、MacのクリップボードからWindowsのクリップボードへの貼り付けみたいなことも、ある程度自動的に実行できるようになる。「なんちゃってユニバーサルクリップボード」といったところだ。

作成したサーバとシェルスクリプトで動作を確認

では、作成したサーバとシェルスクリプトの動作を確認してみよう。まず、Windows側でサーバ(winclipserver.ps1)を実行する。

  • Windows 11でサーバwinclipserver.ps1を実行

    Windows 11でサーバwinclipserver.ps1を実行

次に、Macからcalコマンドの実行結果をwinclipコマンドに流し込んでみる。

  • Mac - macOS 12.3

    Mac - macOS 12.3

  • calコマンドの実行サンプル

    calコマンドの実行サンプル

  • calコマンドの実行結果をwinclipシェルスクリプトに接続

    calコマンドの実行結果をwinclipシェルスクリプトに接続

実行後にWindowsで動作しているwinclipserver.ps1を見てみると、次のスクリーンショットのようにシステムクリップボードへのコピーが行われたことを示すログが表示される。

  • winclipserver.ps1 - システムクリップボードへのコピーを実行

    winclipserver.ps1 - システムクリップボードへのコピーを実行

この状態でメモ帳を起動して貼り付けを行ってみる。

  • メモ帳を起動

    メモ帳を起動

  • 「Ctrl」+「V」で貼り付けを行ったあと

    「Ctrl」+「V」で貼り付けを行ったあと

Macで実行したcalコマンドの実行結果が貼り付けできていることを確認できる。

なるべく手を抜けるようにプログラミングを行う

シンプルなアイデアで実装も簡単なものだが、すでに結構実用的だ。例えば、いつもはLinuxで作業していて、そこからテキストデータを持ってきてWindowsで利用したい場合などには、こういった仕組みを用意しておくとかなりシームレスに作業を行えるようになる。「しなくてもよい手間」とは、プログラムに自動的に処理させるのがよいのだ。そこに人手をかけるのはなるべく避けたい。

さらにブラッシュアップを続けて、さらに手を抜ける状況にしていこう。