ログオン時にドライブ文字が現れ、その後、空のフォルダーとして開くか、赤い×印とネットワークリソースが利用できないというメッセージとともに開く。アクセス許可はたいてい問題ない。起きたのは、VPN クライアントは存在するがファイルサーバーへの経路がない時間帯に割り当てコマンドが実行され、Windows がその失敗をドライブの状態として記録したことだ。修正は、割り当てをログオン時に起きるものとして扱うのをやめ、接続シーケンスの最後の手順として扱うことにある。

割り当てが早すぎる理由

サインインスクリプトはセッションの開始とともに始まる。ログオン中に接続する VPN クライアントは独自の時間軸をその上に重ねる。プロセスは動いていてもよく、仮想アダプターは存在していてもよく、オフィスのサブネットへの経路はまだなくてもよい。スクリプトから見るとこの三つの状態は同じに見え、機能するのは一つだけだ。

環境によっては毎回のログオンで同じ失敗行を繰り返す対応をしており、その結果、ドライブを二回クリックすることを覚えた利用者と、一度も自力で成功したことのないスクリプトが残る。

ドライブ自体が事態を悪くする。割り当てられたドライブはセッションのオブジェクトであり、Windows が利用不可と記録した後は、トンネルが正常になってからもアイコンが壊れたまま残ることがある。手作業での再割り当てがうまくいくのにスクリプトは何もしていないように見えるのはそのためだ。セッションは失敗を覚えており、その背後にあった意図は覚えていない。

接続済みという状態は経路ではない

タスクトレイの VPN アイコンはトンネルが上がっているかどうかを伝える。特定のサーバーへの経路があるか、DNS がその名前をトンネルのアドレスに解決するか、サーバー自身のファイアウォールが自分を受け入れるかについては何も言わない。

これは見た目の結果が同じ三つの別々の失敗であり、トレイアイコンを基準にすると一つの信頼できない信号に溶け合ってしまう。

本当に必要なサーバーを名指しする準備確認なら、これらを区別できる。特定の経路が通るまで失敗し、どこかのインターフェースが接続済みと報告した時点で成功するわけではないからだ。

クライアントではなくサーバーを基準にする

トンネル経由でしか到達できないホストを一台選び、何かを割り当てる前にそれを待つ。以下の断片は保存済みの Windows VPN エントリに接続し、ファイルサーバーをポーリングしてからドライブを割り当てる。

@echo off
set server=fileserver.corp.example
rasdial "Office VPN" /disconnect
rasdial "Office VPN"
:wait
ping -n 1 -w 1000 %server% >nul || (
  timeout /t 5 /nobreak >nul
  goto wait
)
net use Z: \\%server%\share /persistent:no

ping は準備確認であり、アクセス許可のテストではない。ネットワークで ICMP がフィルターされている場合は、実際に使うサービスを代わりに確認する。手早い確認なら net view \\%server%、PowerShell でポート 445 に対する短い TCP テストでもよい。どちらも重要なものを基準にしている。

試行回数に上限を設ける。上限のない待機ループは、壊れたトンネルをログオンが終わらないセッションに変えてしまい、それはドライブ文字がないことより厄介なサポート案件になる。

再実行可能でセッションを意識したものにする

ユーザー自身のセッション内で実行する。SYSTEM として実行するタスクはドライブをまったく別のセッションに置くため、ログオン中のユーザーには結果が見えない。すると成功を報告するスクリプトと、ドライブのないデスクトップが残る。

割り当てる前に確認し、古いエントリだけを削除する。net use Z: /delete は文字が使われていないときにエラーを返すが、そのエラーは無視してよく、スクリプトの残りを捨てる理由にはならない。/persistent:no を付けておき、失敗した試行が後から恒久的な再接続の試行に変わらないようにする。

そしてファイルにパスワードを書かない。rasdial は VPN エントリ用に保存された資格情報を再利用でき、共有はサインイン中のユーザーとして認証されるべきだ。共有に本当に別の資格情報が必要なら、ログオン共有上に置かれたバッチファイルに埋め込むのではなく、cmdkey でユーザーごとに一回登録する。その共有を読める者はパスワードも読めるわけで、それは便利さをインシデントに変えてしまう。

スクリプト全体を再実行しても無害であるべきだ。実際にそうなるからだ。利用者は再接続し、ノート PC はスリープから復帰し、同じコード経路が異なる初期状態でまた走る。

どちらが遅れたのかを証明できるだけ記録する

タイムスタンプ、準備確認の結果、割り当ての終了コードをユーザープロファイル配下のファイルに書き出す。次にドライブがないという報告が来たとき、そのログが唯一重要な問いに答える。トンネルが遅れて来たのか、共有が拒否したのか。

それがなければ、再発のたびにゼロから調査することになり、たいていは何も直らないアクセス許可の変更という結論になる。

コールドブートから一回、スリープから一回、この順序を試す。順序が最もよく崩れるのは復帰の場合だ。ネットワークより先にセッションが再開し、スクリプトは何時間も前にログオンしたマシンを見ることになる。

関連記事