客先のWindows端末でファイル同期を自動化した話
客先のWindows端末で、担当者が手でやっていたフォルダのコピーを常駐スクリプトで自動化した。robocopyとFileSystemWatcherで組んだ実装と、更新時に既設の設定を壊さない勘どころを、作った側の視点でまとめる。
客先のWindows端末で、担当者が手でやっていたフォルダのコピー。 これを、端末に置いた常駐スクリプトで丸ごと自動化しました。
やっていることはシンプルです。 ローカルの作業フォルダで変更があったら、 共有サーバーへ一方向で黙って追従する。それだけ。 道具も robocopy と FileSystemWatcher、Windows に元からあるものだけで組みました。
派手なプロダクトではありません。 でも「人が手でコピーする限り、抜け漏れは必ず出る」—— 現場のその実感から生まれた自動化です。
この記事で書くのは、実際に動いている実装のかたちと、 引き渡したあとに一番こわい「既設端末の設定を壊す」事故をどう避けたか。 受託先の小川建機様向けに作った側の視点で、まとめます。
📋なぜ手作業をやめたかったか
手でコピーする限り上げ忘れは必ず出る。判断のいらない転記だからこそ、端末側で自動反映して抜け漏れを構造から消した。
免許証や車検証といった安全書類を、担当者がまずローカルの作業フォルダに置く。 あとで共有サーバーの所定の場所へコピーする。 そういうフローが日常的にありました。
作業自体は数秒です。 でも忙しいと後回しになる。そして「サーバーに上がっているはず」の ファイルが、実は無い。 この食い違いが、探す時間と「本当に最新か」という不安を生みます。
コピーという行為に、判断は要りません。 だったら端末側で勝手に反映されるようにすればいい。 抜け漏れという事象そのものが、構造から消えます。 そこで、 ローカルで変更があったら共有サーバーへ黙って追従する常駐スクリプトを設計しました。
⚙️実装 — 検知とポーリングのハイブリッド
コピー処理はrobocopy任せ。イベント監視に5分ごとのポーリングを重ね、取りこぼしを保険で拾う二段構えにした。
中身はシンプルです。 コピー処理そのものは Windows 標準の robocopy に丸投げしています。
変更の検知は FileSystemWatcher のイベント監視が主軸。 そこに、 取りこぼしの保険として5分ごとの定期ポーリングを併走させました。 イベントだけに頼ると、ネットワークが一瞬切れた隙の変更を拾い損ねることがあるからです。
正直、作り込みの大半は機能ではなく「安全に倒す」ための細部でした。
ローカルで削除しても共有サーバー側は残す(削除は同期しない)。 ネットワーク切断を検知したら、復旧時に全同期し直す。 同じフォルダへの変更が連打されたら、10秒のデバウンスで robocopy の多重起動を抑える。 ログは容量でローテーションして、数世代だけ残す。 desktop.ini や Office の一時ファイルは、同期対象から外す。
常駐化はタスクスケジューラの「ログオン時」トリガーに登録しました。 端末を立ち上げれば、勝手に動き出します。
🗂️一番の落とし穴 — 既設端末の設定を上書きしない
怖いのは機能より更新手順だ。環境依存の同期ペアは別ファイルに切り出し、本体だけ差し替えて設定を巻き込まないようにした。
受託の自動化で本当に神経を使うのは、実は機能ではありません。 更新手順のほうです。
このスクリプトは「どのフォルダとどのフォルダを対応させるか」という同期ペアを9組もっています。 サーバー名やユーザー名を含む、環境依存の値です。
だから設定を本体コードから切り離し、config.local.ps1 という別ファイルに逃がしました。 このファイルは Git 管理外(.gitignore)で、端末ごとに現地で作ります。
なぜ分離が効くのか。 本体の watch_sync.ps1 を新しいバージョンに差し替えても、同期ペアの定義には一切触れずに済むからです。
逆に、ここを取り違えて config.local.ps1 ごと上書きしたら? 9ペアの設定が吹き飛びます。 現場では「昨日まで動いていた同期が、止まった」 という形で表面化する。いちばん避けたい事故です。
だから README にも「config.local.ps1 は絶対に上書きしない」 と赤字級で残しました。 更新前に .bak へ退避してから、本体だけ差し替える。 この手順に固定しています。
🚧設定が無いなら「動かない」を正解にする
設定ファイルが無いまま走ると誤同期を撒く。だから未設定なら黙って止まる挙動を、安全側の初期設計として組んだ。
環境依存値をリポジトリに置かない方針には、もう一つ副作用があります。 clone した直後は設定ファイルが無いので、そのままでは動きません。
これを不便と捉えるか、安全と捉えるか。 私は後者にしました。 設定が無い状態で起動したら、起動ログにエラーを書いて止まる。いわゆる fail-closed です。
中途半端に空の設定で走り出すと、意図しない場所へファイルを撒く「誤同期」が起こり得ます。 誤同期は、削除同期なしの設計でも回収が面倒です。
「設定が揃っていないなら、黙って止まる」。 これを正解にしておくほうが、受け渡し先の端末で事故が起きにくい。
リポジトリに実際の9ペアは置きません。 雛形の config.local.example.ps1 だけを置き、 実値は既設端末から退避するか、安全な保管先から取り出す運用にしています。
これは開発の一般論としても知られる、設定とコードの分離という考え方に沿っています(The Twelve-Factor App: Config)。
💡地味だが効く受託自動化の勘どころ
効いたのは高度な技術ではない。環境依存値の分離、上書きしない手順、無ければ止まる安全側。この3点が仕上がりを分けた。
振り返ると、この案件で価値になったのは高度な技術ではありませんでした。 robocopy も FileSystemWatcher も、Windows に元からある道具です。
効いたのは、もっと地味なところ。 環境依存値をコードから分けたこと。 更新時に設定を上書きしない手順を、紙に固定したこと。 設定が無ければ黙って止まる、安全側の挙動。 この3点でした。
客先の端末は、開発者の手元ではありません。 次に触るのが半年後の自分か、引き継いだ誰かかもしれない。 そう思うと、機能より「壊しにくさ」のほうが怖い。だから最初から作り込んでおく。
手作業のコピーを消す——そんな小さな自動化ほど、こうした運用の設計が仕上がりを分けます。 i-Willink では、現場で詰まる落とし穴を構造から潰す受託を続けています。 もし社内に「人が手でコピーしている限り抜けるフロー」が残っているなら、一度、 構造から見直してみてください。
開発パートナーを探していますか?
AIでプロダクトを最速で形にしませんか?
最短1週間でMVPを開発。アイデアの検証から本番リリースまで、i-Willinkがフルサポートします。まずはお気軽にご相談ください。
無料で相談する