WSLをSSHから使えなくて苦労したおはなし

この記事について

 この記事は、SSH経由でWSL上で何らかの処理を実行するため、散々回り道をしたのちに、極めて愚かな方法で解決したことについての覚え書きです。実際には途中で発生した問題に解決出来たものがあるのかもしれませんが、筆者が試した範囲で解決出来なかったものについては検討しません。
 この記事については、関連する情報を歓迎いたします。ぜひコメントをお寄せください。内容を検討し、場合により記事をアップデートします。

この記事の論点について

 この記事は、以下のような内容を含みます。
・iOS/iPadOSからプリントする際のストレス軽減策
 →他にプリントサーバを用意する。
・WindowsPowershellから印刷を実行する際に指定した設定値が無視されることへの対応策
 →Windowsでの実行を諦め、Linuxのlpコマンドを使う。
・wsl.exeがSSHセッション上のPowershellから実行できない問題の回避策(これが本稿の本論だが結論は悪手)
 →実行したいコマンドの内容をテキストファイルに書き込み、その内容をWSL側で読み取って実行するようにする。
・Windowsの起動時(厳密にはGUI上での特定ユーザへのログイン時)にPowershellスクリプトを自動実行させる方法
 →スタートアップを使う。

この記事の前提について

 この記事では、3つのデバイスを主に登場させます。なお、これらは筆者の所有するデバイスではなく、それにより採用可能な解決策がいくつか排除されています。
 1つ目はWindows11が搭載されたWindowsマシンで、これは毎日起動し、夜にはシャットダウンします。今回の問題は常識的に考えればOSのサポート外機種だからどうとかいう類の問題ではないのですが、このマシンはきちんとWindows11のサポート対象機種なのでこの手の指摘は不要です。
 2つめはiPad(第8世代)です。検証時の環境はiPadOS16.4からiPadOS16.5です。
 3つめはビジネス用複合機です。本論にあまり関わらないので詳細は伏せます。
 また、これ以外のデバイスを追加することによる問題解決はしない前提です。具体的に言うとRaspberry PiなどLinuxディストリビューションをネイティブ実行する環境を別に用意することですが、この方法は採りません。
 そして、「検討したこと(時系列順)」では、上記のものとは別のWindowsマシン(こちらはWindows10)を使っています。なお、このマシンを上記のWindows11マシンの代わりに本番環境として用いることもしません。

 そして、今回の問題は、基本的にiOS/iPadOSの標準印刷機能であるAirPrintの機能、またAirPrintとこの複合機の組み合わせへの不満によります。以下に羅列します。なお、本稿ではAirPrintはiOS/iPadOSのものを指し、macOSのAirPrintは扱いません。
・プリンタが認識されるまで用紙などの設定を変更できない
 おそらくプリンタにもよるのでしょうが、筆者の環境で使用している複合機の場合、まずプリント設定の画面が表示されてから当該複合機が認識されるまで十秒弱かかり、そこで初めてプリセットが読み込まれ、それまでの間にカラーなどの設定を変更してもプリセットの設定値で上書きされるため、設定が出来ません。さらにこのプリセットの値がカラー印刷になっているのですが、基本的に白黒しか使わないため、これを毎回変更する手間もあります。一方、このプリセットを新しく作成する方法も分かりませんでした。プリセットの値は複合機側の問題で、複合機が認識されるまで時間がかかることと、プリセットの作成ができないと思われるのは複合機とAirPrintのどちらの問題であるか分かりません。
・プリント指示をしてから実際にプリントされるまでの時間が長い。
 Windowsマシンなどからプリントするとすぐに印刷されるのですが、AirPrintからプリントすると、「プリント」ボタンを押してから実際にプリントが開始されるまで(iPadOS上で「プリントセンター」が表示され、複合機のジョブ一覧に当該ジョブが表示されるまで)に、バラツキがあるものの数十秒かかります。これがどちらの問題かは分かりません。
・両面印刷で短辺綴じか長辺綴じかを選択出来ない
 これはAirPrint側の問題ですが、AirPrintでは(確か)長辺綴じになります。これを回避するため、「ファイル」Appの機能で偶数ページを180度回転させるという対応をしていますが、これも非常に手間です。

 また、いくつかのファイルを一式としてプリントする場合に、ファイルによって用紙サイズが異なる場合など、各ファイルについて設定を変更し、また印刷するのが手間であるため、これを自動化したいという需要が私の中に存在しました。ここでプリントするファイルはPDFファイルで、基本的にその場限りのものではなく、あらかじめ用意しておいて必要に応じて何回も印刷する類のものです。

検討したこと(時系列順)

1.WindowsPowershellから印刷を実行、iPadからはショートカットAppでSSH経由でPowershellにアクセス

 つまりは、Windowsマシンによく印刷するPDFファイルを配置しておき、Powershellで印刷を実行する方法です。Start-Processの-VerbにPrintを指定します。iPadからも同様のコマンドを実行します。
 この手法で起きた問題は、用紙やカラーなどの設定を引数で指定しても、OSでセットアップされているプリンターの、そのOSで標準になっているプリセットの設定値が適用されてしまうことでした。これがWindowsの標準機能の問題なのか、この複合機のドライバの問題なのか、はたまた他の所に問題があるのかは不明です。

2.同一の複合機を各別のものとして、Windowsに複数個インストールする

 先の方法では、使用するプリンタは指定できたため、使うことが予想される設定値の組み合わせの数だけその複合機をWindowsにインストールして、それぞれに異なるプリセットを標準として指定することで、プリンタを指定するだけで適切な設定値を適用させようという試みです。
 ですが、これは複数回同一のドライバをインストールしても、既存のそのドライバが上書きされるだけという極めてシンプルな失敗に終わりました。ネット上には複数個インストールすることが可能だという情報があったのですが、筆者の環境では出来ませんでした。一応、その複合機が対応している別のプロトコルでインストールすると複数個のインストールも出来た(それなりに時間が経っているのでうろ覚え)のですが、それでは必要なプリセット数に足りませんでした。

3.Linux上から印刷する

 WSL(2)側のローカルIPアドレスを固定する方法についてはネット上でいくつかの手法が提案されているのですが、筆者のネットワークに関する貧弱な知識では運用に不安があったなどの理由から、起動の度に変更されるWSL2側のローカルIPアドレスは、毎度、wsl.exeのeオプション経由でWSL側のipコマンドから取得し、そのアドレスに直接SSHでアクセスし、lpコマンドで印刷することを考えました。lpをwsl.exe経由で実行しなかったのは、筆者がPowershellに慣れていないため、eオプションを用いた際の特殊文字の扱いなどに関する知識がなく、直接bashにアクセスした方が確実だと判断したためです。
 Linux上から印刷するには、cupsなどをインストールし、プリンタの設定を済ませ、lpコマンドを叩けばよく、これは上手く働きました。
 Windows10マシンのWSL上ではcupsが自動起動されないといった課題がありましたが、これは本番環境のWindows11マシンでは発生しませんでした。 

最も手こずった問題

WSLをSSH上から実行できない

 ですが、本番環境のWindows11マシンに同様の環境を展開したとき、wsl.exeがSSH上のPowershellから実行できないという問題が発生します。wsl.exeを実行すると「ファイルにアクセスできません」というエラーメッセージが表示され、失敗するものです。これはWindows10マシンでは発生しませんでしたが、ネット上にはWindows10環境でも発生したという報告があるようです。
 wsl.exeが実行できないということは、その環境からは「直接的には」一切WSL側にアクセス出来ないということを意味します。そのため、主としてiPadから印刷指示をする関係上、このWindows11マシン上のWSLを利用することは不可能かと思われました。
 このエラーはネット上にも報告があり、いくつかの原因と対応が考えられているようです。以下にそれぞれについて筆者の環境での結果を示します。
・ストアアプリ版をアンインストールすると解決するというもの
 そもそもwslコマンドを利用してインストールしていたので採れませんでした。現在ではwslコマンドでもストアアプリ版がインストールされるのか、詳細は不明です。
・あるセキュリティアップデートをアンインストールするというもの
 セキュリティに影響を及ぼしかねない方法については回避する方針を採りました。そのため、当該アップデートが適用されているか否か自体を確認していません。
・ストアアプリの格納されているフォルダの権限を変更するというもの
 こちらもセキュリティに影響を及ぼしかねないため回避しましたが、こちらはさらにOS自体の動作に影響を与えうるため、採りませんでした。なお、筆者個人所有のWindows11マシンでこれを試しましたが、解決しませんでした。
・Win32側のユーザ名とWSL側のデフォルトのユーザ名が異なるとエラーになるため、これを合わせるというもの
 これは本番環境のマシンでは試すことが出来ませんでした。というのは、本番環境のマシンはMicrosoftアカウントでサインインされており(Windows11のためこれはほとんど必然)、この場合Windowsの内部ユーザ名はMicrosoftアカウントのID(というよりはおそらくメールアドレス)の最初の数文字を取ってWindowsが勝手に決定するのですが、この環境ではそのユーザ名にドットが含まれていました。
 一方で、WSLでUbuntuをインストールすると、最初のログイン時にユーザとパスワードを作成するのですが、このときのユーザ名にはドットを含むことが出来ないため、Windows側の内部ユーザ名と合わせることが出来ませんでした。ここで作成したユーザ名を後から変更し、Windowsの内部ユーザ名と合わせることは出来たのですが、それでは解決しませんでした。
 そのため、筆者個人所有の環境でもこれは検証していません。

 結局、この問題を根本的に解決することは出来ませんでした。そこで、つい先日思いついたウルトラCがこちらです。非常に愚かで、地味なウルトラCですが、少なくとも筆者の知識ではこれ以外の解決法が思いつかなかったのです。

Win32側にサービスを用意し、WSL側に実行したいコマンドを渡す

 まず、WSL側で実行したいコマンドを書き込むファイルを用意します。SSHセッションからは、Powershellからechoコマンド(実際にはエイリアスですが)を実行し、リダイレクトでそのファイルに実行したいコマンドを書き込みます。安全のため、末尾に追加ではなく上書きの方が好ましいでしょう。この時、このファイルの改行コードはCRLFです。また、BOMが付いています。
 このファイルの変更を監視し、変更が検出されたときにWSL側に用意したシェルスクリプトをwsl.exeのeオプションで実行するWin32側のサービスを用意します。このサービスはPowershellスクリプトで、用いるのはGet-Content -Waitやforeachなどです。この先、Win32側のサービスを「サービス」、WSL側のシェルスクリプトを「コンパニオンコマンド」、最初に用意した実行したいコマンドを書き込むファイルを「スクリプトファイル」と呼ぶことにします。
 サービスにより実行されたコンパニオンコマンドは、nkfコマンドの-Luオプションにより、スクリプトファイルの改行コードをCRLFからLFに変換します(nkfはUbuntu環境であればaptで導入してください。他のパッケージ管理システムは分かりません)。このときBOMも取り除かれます。これを別のファイルに保存し、「LFファイル」と呼ぶことにします。LFファイルを作る場合も、リダイレクトで上書きするのがよいでしょう。
 次に、LFファイルの内容をifなどで比較し、それが空であるかを確認します。空でない場合にはcatでLFファイルの中身をbashに流し、コマンドを実行し、最後にスクリプトファイルの内容を空にします。これでコンパニオンコマンドの処理が終了します。
 スクリプトファイルが空になったことも変更であるため、もう一度サービスがコンパニオンコマンドを実行しますが、コンパニオンコマンドは、スクリプトファイルが空である場合にはtrueなどを実行し、何もしません。これでコンパニオンコマンドの処理が終了し、サービスが再び待機状態に戻ります。
 なお、iPadからスクリプトファイルに書き込む際、「ショートカット」AppからSSH経由でPowershellを使うのではなく、同じく「ショートカット」Appから「ファイル」Appの機能を利用すればよいのではないかという指摘があるかもしれませんが、「ファイル」Appの「サーバへ接続」機能は再接続に失敗する頻度が極めて高いため、採用していません。

Powershellスクリプトを起動時に実行する

 まず、タスクスケジューラを使った方法は筆者個人所有の環境でのテストで上手く行きませんでした。これがなぜ失敗したのかは不明です。
 そこで、スタートアップにショートカットを作成することにしました。「shell:startup」をエクスプローラのパスバーに入力することで表示出来ますが、このフォルダにショートカットを作成し、プロパティからリンク先をPowershellの実体に指定し、起動時に画面を表示したくなければ-WindowStyle Hiddenを指定し、最後にサービスのパスを指定すれば済みます。一瞬だけウィンドウが表示されることも、起動時のウィンドウサイズを最小化に指定しておけば多くの場合問題にならないでしょう。

最後に

 結局の所、wsl.exeを実行できない問題を解決出来なかったため、スクリプトとしての実行のみで、対話利用が出来ないことが大きな課題として残っています。
 Microsoftに対しては、このようなバグの早急な修正を求めるとともに、(この不具合の原因であるか否かにかかわらず)Microsoftアカウントでのユーザ作成を強要する方針を変更すること、内部ユーザ名の重要性を認識し、ユーザが任意のユーザ名を作成出来るようにすることをも求めます。Microsoftのサポートコミュニティには関わりたくないので私からは何もしませんが。
 正直、どうしてもWSLしか利用できないという筆者のような特殊事例でなければ、ネイティブのLinuxを利用する方が安全だと思います。Windows Updateの内容によってWSLにログイン出来なくなるというのは、はっきり言って信頼性が全くありません。cupsがなぜか立ち上がらないなどの問題も起きないはずで、この記事のうちWindowsの関わる問題は全て回避できます(というより、Linux単体の問題が何も発生していない)。
 あと、この複合機は、UIも使いづらければ動作速度も大して速くなく、不要な通知は期限が切れるまで何回でも狭い画面上にでかでかと復活し、しかもコピーの際に連続してスキャンする際の段取りも悪く、スタートなどの極めて基礎的な物理ボタンすら排除したせいでスタイリッシュになったかと思えば連絡先以外の機能は何ら登録できない昔ながらの18個のボタンは残っているせいで見た目も悪いというどうしようもない機種で、私は自分で複合機を選ぶことがあればこのメーカのものは絶対に選ばないと心に決めています。あと社名がダサい。

この記事が気に入ったらサポートをしてみませんか?