ネットワークドライブとUNCパスの落とし穴 ── 業務アプリでファイルサーバー(共有フォルダ)を扱う実務

· 更新日: · · ネットワークドライブ, UNCパス, SMB, ファイル共有, Windowsサービス, ファイルサーバー, C#, .NET, ネットワーク, 不具合調査, Windows開発, 技術相談

更新履歴(3件・最終更新 2026年08月02日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
想定する環境(OS、共有プロトコル、認証基盤、アプリの実行形態、コード例の前提)を冒頭の表で明示しました。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.21590016)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「ネットワークドライブとUNCパスの落とし穴 ── 業務アプリでファイルサーバー(共有フォルダ)を扱う実務」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21590016 https://staging.comcomponent.com/blog/network-share-unc-path-pitfalls/

DOI(最新版)
10.5281/zenodo.21590016
DOI(この版)
10.5281/zenodo.21732993

「開発機では動いていたのに、お客様の環境で『Z:\ が見つかりません』と言われる」「タスクスケジューラに載せた途端、共有フォルダへの出力が失敗するようになった」「Windowsサービス化したらファイルサーバーが見えなくなった」── 業務アプリの相談で、ファイルサーバー(共有フォルダ)絡みのトラブルは定番中の定番です。受注データの取り込み、帳票やCSVの出力、装置が吐くファイルの監視。オンプレの業務システムでは、共有フォルダは今も現役の連携基盤だからです。

厄介なのは、この種のトラブルの多くが「コードのバグ」ではなく、ドライブ文字とログオンセッションの関係、サービスの実行アカウントと認証、SMBの接続管理といったWindows側の仕組みに根ざしていることです。デバッガーで追っても原因にたどり着けず、「自分のPCでは再現しない」まま時間が溶けていきます。

この記事では、共有フォルダへのファイル出力・取り込み・監視を実装する業務アプリ開発者(WinForms/WPF/Windowsサービス)を対象に、ネットワークドライブとUNCパスの落とし穴を仕組みから整理し、実務の定石を判断表にまとめます。

想定する環境

認証まわりの話は前提が変わると答えも変わるため、先に想定環境を明示しておきます。

項目 想定
OS Windows 10 / 11、Windows Server(現行のサポート対象バージョン)
共有プロトコル SMB(Windowsの標準的なファイル共有)
認証基盤 Active Directoryドメイン環境を主に想定。ドメインのないワークグループ環境やNASの独自アカウントを使う場合は、その都度「ワークグループでは」と断って区別します
アプリの実行形態 デスクトップアプリ(WinForms / WPF)、Windowsサービス、タスクスケジューラから起動されるコンソールアプリ
コード例 C# / .NET 6以降(File.WriteAllBytesAsync と、is ... or ... のパターンマッチを使用しています)

ドメインかワークグループかは、この記事で最も効く分岐です。第3章の実行アカウントの選択肢(コンピューターアカウントやgMSA)はドメインがあって初めて成立し、ドメインがない環境では第4章の「明示的に資格情報を渡す」方向に寄ることになります。自社がどちらかを先に確認してから読み進めてください。

この記事で使う略語

略語 読み・正式名称 ひとことで言うと
UNCパス Universal Naming Convention(ユニバーサル命名規則) \\サーバー名\共有名\... の形式。共有フォルダーの本来の住所
SMB Server Message Block Windowsのファイル共有で使われる通信プロトコル
ログオンセッション ユーザーがログオンしたとき、あるいはサービスが起動したときにOSが作る「実行の文脈」。ドライブ文字はこの単位で管理される(第2章)
Kerberos Active Directoryドメインの標準的な認証プロトコル。チケットをやり取りして本人確認する
SPN Service Principal Name(サービスプリンシパル名) Kerberosで、接続先のサービスを一意に指すための名前。クライアントは接続先ホスト名からSPNを組み立ててチケットを要求する(第4章)
gMSA group Managed Service Account(グループ管理サービスアカウント) パスワードをOSが自動生成・自動更新してくれるドメインのサービスアカウント(第3章)1

1. まず結論

  • ドライブ文字(Z:など)はシステム全体のものではなく、ログオンセッション単位のものです。ログオンセッションごとにAからZのドライブ文字一式が割り当てられるため、別ユーザーのプロセス、別のログオンセッションで動くサービスからは、ユーザーがマップしたドライブは見えません。2
  • UACが有効な管理者では、通常権限と昇格用の2つのログオンセッションが作られ、ドライブマップ(DosDevicesのシンボリックリンク)はセッションごとに独立します。だから「昇格したアプリからだけZ:が見えない」が起きます。EnableLinkedConnections レジストリで両セッションに共有させる回避策は存在しますが、Microsoftが「システムを安全でなくする可能性があり、サポートしない」と明記する非サポート設定です。34
  • サービス(や異なるセキュリティコンテキストのプロセス)からリモート資源にアクセスするときは、UNCパス(\\server\share\...)を使うのが公式の指針です。サービス内から net use やWNet系APIでドライブ文字をマップする実装は、資格情報の漏えいやサービス間の干渉の観点から推奨されていません。2
  • 共有側で権限を与える相手は、サービスの実行アカウントで決まります。LocalSystemとNetworkServiceはネットワーク上では「コンピューターの資格情報」として認証され、LocalServiceは匿名資格情報になるため共有アクセスには不適です。ローカルユーザーアカウントのサービスはネットワーク資源にアクセスできません。実務の本命はドメインアカウントか、パスワード管理をOSに任せられるgMSA(group Managed Service Account、グループ管理サービスアカウント)です。ただしgMSAはドメイン環境とKDSルートキーの準備が前提になります(第3章)。567819
  • 同じサーバーに対して複数の資格情報で同時接続はできません。2つ目の接続はエラー1219(ERROR_SESSION_CREDENTIAL_CONFLICT)で失敗し、これは仕様(by design)です。1011
  • 共有フォルダは「遅い・切れる・いないことがある」が正常系です。アイドルな接続は既定で15分後にサーバー側から切断されます(次のアクセスで再接続)。File.Exists は権限不足やエラー時にも例外を出さず false を返すため、「ファイルが無い」と「サーバーに届かない」を区別できません。1213
  • FileSystemWatcherはネットワークドライブやリモートコンピューターの監視をサポートしますが、取りこぼし前提で設計します。バッファあふれでイベントを失うことがあり、ネットワーク越しの監視では内部バッファの上限が64KBに制限されます。ポーリング(フルスキャン)の併用が定石です。14

この記事の知識マップ

業務アプリから共有フォルダーへ出力・監視するトラブルの多くは、コードのバグではなくWindowsの仕組みに根ざしている。ドライブ文字はログオンセッション単位のシンボリックリンクにすぎず、別ユーザー・UAC昇格・サービスからは見えないため、サービスや異なるセキュリティコンテキストのプロセスはUNCパスを使うべきとされる。サービスからの認証は実行アカウントで決まり、LocalSystem/NetworkServiceはコンピューターの資格情報、LocalServiceは匿名資格情報になるため、ドメイン環境ではドメインアカウントかgMSAに共有側の権限を与えるのが実務の標準になる。同じサーバーへの複数資格情報の同時接続はエラー1219で失敗する仕様があり、共有は遅い・切れる・いないことがあるという前提のもとtemp→renameでの公開やidempotencyな再処理、FileSystemWatcherとポーリングの併用で設計しておく必要がある。

ネットワークドライブとUNCパスの落とし穴の知識マップドライブ文字がログオンセッション単位でしか通用しないこと、サービスの実行アカウントごとに共有側の認証が変わること、エラー1219や共有の切断・取りこぼしを前提にした設計が必要になることの関係を示す図に保存される推奨される対応用いるのは非推奨前提とする両立しない用いるのは非推奨推奨される対応前提とする前提とする用いるのは非推奨推奨される対応前提とする前提とする推奨される対応前提とする前提とする前提とする利用する前提とする原因になり得る推奨される対応推奨される対応推奨される対応推奨される対応推奨される対応推奨される対応推奨される対応防止する用いるのは非推奨前提とする原因になり得るUNCパスログオンセッションネットワークドライブ(マップされたドライブ文字)WindowsサービスUAC昇格(管理者として実行)EnableLinkedConnectionsレジストリ値LocalSystemアカウントActive Directory(AD DS)NetworkServiceアカウントLocalServiceアカウントgMSA(group Managed Service Account)ドメインコントローラードメインアカウントKerberosSPNネットワークリダイレクターSMB(TCP 445)net use コマンドエラー1219(ERROR_SESSION_CREDENTIAL_CONFLICT)WNetAddConnection2資格情報マネージャー(cmdkey)偽装(impersonation)FileSystemWatcher共有フォルダ(SMB)越しのファイル連携定期フルスキャン(ポーリング)temp -> close -> rename/replaceでの公開idempotency(冪等性)を前提にした処理書き込み途中ファイルの読み込み事故File.ExistsSMBのアイドル接続自動切断(autodisconnect)

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全31件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

2. ドライブ文字とUNCパスの関係 ── Z:は「あなたのログオンセッション」のもの

エクスプローラーで \\fileserver\share をZ:に割り当てると、いかにもマシン全体に「Z:ドライブ」が生えたように見えます。これが最初の誤解です。

公式ドキュメントの記述は明快です。ドライブ文字はシステムグローバルではなく、ログオンセッションごとにAからZの一式が割り当てられます。リダイレクトされたドライブ(ネットワークドライブ)は異なるユーザーアカウントで動くプロセス間で共有できず、別のログオンセッションで動くサービスは、他のセッションで確立されたドライブ文字にアクセスできません。2 システムはドライブマップを、ログオンセッションを一意に識別するログオンSIDに基づいて管理しています。2

つまりZ:は「パスの短縮記号がログオンセッションに1セットずつある」だけで、実体は常にUNCパスです。図にすると次のようになります。

ログオンセッション B ── サービス / タスクスケジューラログオンセッション A ── 対話ログオンした利用者Z: で到達できるZ: は存在しない。UNCパスなら到達できるWindowsサービススケジュールされたバッチこのセッションのドライブ文字一式Z: は未割り当てエクスプローラーデスクトップから起動したアプリこのセッションのドライブ文字一式Z: は共有にマップ済み共有フォルダーの実体UNCパス ── fileserver01 の share

図1: ドライブ文字はログオンセッションごとに1セットあり、実体のUNCパスはひとつしかない

注意したいのは、この分離が「ユーザーが違うから」ではないことです。サービスをセッションAと同じユーザーアカウントで実行するよう構成しても、システムはサービス用に新しいログオンセッションを作るため、セッションAで張ったマップは引き継がれません。2 「サービスの実行ユーザーを自分と同じにしたのに、まだZ:が見つからない」という相談は、ここを取り違えていることが原因です。

ここから、現場で頻発する症状が芋づる式に説明できます。

症状 仕組み上の理由
別ユーザーで実行したらZ:が無い ドライブ文字はログオンセッション単位。他人のマップは見えない2
「管理者として実行」するとZ:が無い UACで通常用と昇格用の2つのログオンセッションが作られ、マップは共有されない3
タスクスケジューラ/サービスに載せたらZ:が無い 別のログオンセッションで実行されるため。サービスをユーザーアカウントで構成しても、システムはサービス用に新しいログオンセッションを作る2

UACの件はもう少し詳しく押さえておく価値があります。管理者グループのユーザーがログオンすると、システムは権限を制限したトークンと完全な管理者トークンの、リンクされた2つのログオンセッションを作ります。ドライブマップの実体はドライブ文字とUNCパスを対応付けるシンボリックリンクオブジェクト(DosDevices)で、これはログオンセッション固有であり、セッション間で共有されません。3 ログオンスクリプトは通常権限側で走るので、昇格したプロセスからはそのマップが見えない、という理屈です。

EnableLinkedConnections(HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System のDWORD値)を1にすると、リンクされた2つのセッションの両方にシンボリックリンクが書き込まれ、この症状は消えます。ただし公式ドキュメントには「この回避策はシステムを安全でなくする可能性がある。Microsoftはこの回避策をサポートしない。自己責任で使用すること」と明記されています。4 お客様環境のレジストリに非サポート設定を仕込む提案は、業務アプリの解決策としては筋が悪い。アプリ側をUNCパスで書くのが正道です。フォルダーリダイレクトの公式トラブルシューティングでも「ドライブ文字ではなく常にUNCパスの使用を推奨する」とされています。4

実装上はシンプルで、設定ファイルに保存するパスをUNCで持てば済みます。

// appsettings.json ── ドライブ文字ではなくUNCで持つ
{
  "FileTransfer": {
    "IncomingDir": "\\\\fileserver01\\edi\\incoming",
    "ProcessedDir": "\\\\fileserver01\\edi\\processed"
  }
}

ユーザーがフォルダー選択ダイアログでZ:配下を選べてしまうアプリなら、保存時にUNCへ正規化しておくと、後で実行コンテキストが変わっても壊れません。ドライブ文字からUNCへの変換には WNetGetUniversalName というAPIが用意されています。15

3. Windowsサービスから共有フォルダにアクセスする ── UNC必須、そして「誰として」アクセスするか

前章のとおり、サービスからマップドドライブは使えません。公式ドキュメントは、サービス(および異なるセキュリティコンテキストで動くプロセス)はUNC名でリモート資源にアクセスすべきとしたうえで、サービス内で net use やWNet系APIを使って実行時にドライブ文字をマップする実装を明確に非推奨としています。同じコンテキストで動く他のサービスからマップが見えてしまう、net use に渡した資格情報がサービスの境界外に漏れうる、複数サービスが同じマップを張ろうとして「既に接続済み」エラーで干渉する、というのが挙げられている理由です。2

UNCパスにしたら次の問題は認証です。サービスは「誰として」ファイルサーバーにアクセスするのか。これは実行アカウントで決まり、共有側で権限を与えるべき相手もこれで決まります。

実行アカウント ネットワーク上の身元 共有側の権限付与 判断
LocalSystem コンピューターの資格情報5 ドメイン環境ならコンピューターアカウント(DOMAIN\MACHINE$)に共有・NTFS権限 動くが権限が過大。マシン入替で権限設定やり直し
NetworkService コンピューターの資格情報6 同上 ローカル権限は最小でネットワーク上はLocalSystemと同じ身元
LocalService 匿名資格情報7 付与しようがない 共有アクセスには不適
ローカルユーザー ネットワーク資源にアクセス不可8
ドメインユーザー そのアカウント そのアカウントに付与 実務の標準。パスワード変更の運用が課題
gMSA そのアカウント そのアカウントに付与 パスワードはOSが自動管理(30日ごとに自動変更)。対応環境なら本命116

LocalSystemとNetworkServiceが「コンピューターとして」ネットワークに出ていくのは公式に明記された仕様です。56 BITSのドキュメントには、この帰結として「ソースファイルのACLがユーザーアカウントにアクセスを制限している場合、(コンピューター資格情報で認証される)サービスはアクセス拒否になる」「システムアカウントはマップドドライブを使うべきではない」という実務的な注意がそのまま書かれています。17

ここから導ける実務の指針は次の3つです。

  • 「サービスにしたらアクセス拒否」の一次切り分けは、実行アカウントの確認です。デスクトップで動いていたときは「あなた」の権限、サービスでは上表の身元でアクセスチェックされます。共有のアクセス許可とNTFSのACLの両方を、その身元に対して確認します。
  • ドメイン環境で長期運用するなら、ドメインアカウントかgMSAを実行アカウントにします。gMSAは240バイトのランダムパスワードを30日ごとにOSが自動更新するため、「サービスアカウントのパスワード期限切れで月曜の朝に全部止まった」類の事故を構造的に消せます。16
  • ワークグループ環境(ドメインなし)では、コンピューター資格情報での認証が成立しないため、次章の明示的な資格情報の出番になります。

そのgMSAには前提条件があります。「本命」と書きましたが、思い立った日に使えるものではありません。gMSAはもともと、単体サーバー向けのsMSA(standalone Managed Service Account)の機能を複数サーバーにまたがって使えるように拡張したもので、自動パスワード管理とSPN管理の簡素化を提供するドメインアカウントです。1 導入前に次を確認してください。

前提 内容
Active Directoryドメイン gMSAはドメインのアカウントです。ワークグループ環境では選択肢になりません。またWindows Server 2012より前のWindowsには適用されません1
KDSルートキー ドメインコントローラーは、gMSAのパスワードを生成するためにKey Distribution Service(KDS)のルートキーを必要とします。フォレストに一度だけ Add-KdsRootKey -EffectiveImmediately を実行して作成します9
作成後の待ち時間 ルートキーの作成から最大10時間、すべてのドメインコントローラーのAD複製が収束するまでgMSAを作成できません。全DCがgMSAの要求に応えられるようになる前にパスワード生成が起きないための安全策で、「作った直後に使えない」のは仕様です9
管理端末 gMSAを管理するWindows PowerShellコマンドの実行には64ビットアーキテクチャが必要です19
暗号化タイプ gMSAはKerberosのサポート暗号化タイプに依存します。ホスト側でRC4を無効化していて msDS-SupportedEncryptionTypes 属性が無いと認証が必ず失敗するため、MSAには常にAESを構成すべきとされています1

ドメイン管理者との調整が必要な項目が並ぶため、gMSAを前提にした設計を提案するなら、上の5点をインフラ担当者に先に確認するのが順序です。確認が取れない、あるいは10時間の待ちが工程に入らない場合は、まず通常のドメインアカウントで組んでおき、gMSAへの切り替えは実行アカウントの変更だけで済む形にしておくのが現実的です。

サービス自体の作り方(実行アカウントの設定、回復オプション、安全な停止)は「Windowsサービスの作り方と運用」で、セッションとログオンの仕組みは「Windowsのセッション分離をどう理解するか」で整理しています。

4. 資格情報の扱い ── net use・資格情報マネージャー・エラー1219

実行アカウント自体に共有側の権限を与えられない場合(ワークグループ、NASが独自アカウント制の場合など)は、明示的に資格情報を渡して接続することになります。手段は主に3つです。

  • net use \\server\share /user:... ── そのログオンセッションに接続を確立します。対話的な確認には便利ですが、前章のとおりサービス内での実行は非推奨です。2
  • 資格情報マネージャー(cmdkey) ── cmdkey /add:server /user:svc-file /pass:... で保存しておくと、以後そのサーバーへの認証時に保存済み資格情報が自動的に使われます。1819 保存はユーザープロファイル単位なので、サービスで使うなら「サービスの実行アカウントのコンテキストで」登録する必要がある点が落とし穴です。
  • プログラムからの接続(WNetAddConnection2) ── クライアントの資格情報を指定してネットワーク資源への接続を確立できます。公式ドキュメントでも、サーバープロセスがネットワーク資源にアクセスする戦略の一つとして挙げられています。20 ドライブ文字を割り当てない「deviceless接続」にすれば、UNCパスのままアクセスできます。

そして、この領域でもっとも有名な罠がエラー1219です。

Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. (ERROR_SESSION_CREDENTIAL_CONFLICT, 1219)11

同じサーバーに対して、同じログオンセッションから異なるユーザー名で複数の接続を張ることはできません。「営業共有は自分のアカウント、システム連携用の共有は専用アカウントで」と同じファイルサーバーに2種類の資格情報で繋ごうとすると、2つ目が1219で失敗します。公式ドキュメントはこれを「by design(仕様)」と明言しており、回避策として挙げられているのは「IPアドレスで接続する」「別のDNSエイリアスを作って接続する」── つまり別のサーバーに見せかける方法です。10

実務では、そもそも1台のサーバーに複数の資格情報を使い分ける構成を避けるのが第一選択です。連携用アカウントを1つに集約し、必要な共有すべてにそのアカウントの権限を付ける。それができない事情がある場合に限り、別名(エイリアス)で経路を分けます。

ただし、別名は「DNSにCNAMEを1行足せば終わり」ではありません。Kerberos認証の環境では、SMBクライアントは接続先の名前に対応するSPN(サービスプリンシパル名)で認証しようとするため、エイリアスに対するSPNが登録されていないとCNAME経由のアクセス自体が失敗することがあります。公式のトラブルシューティングもこのSPN欠落を原因の一つに挙げ、DNSのCNAMEではなく netdom computername <サーバー名> /add:<別名> でコンピューター名の別名として構成する方法を案内しています。21 エイリアス経由の接続は、1219対策として設計に組み込む前に必ず対象環境で動作検証してください。

なお「サービスが、接続してきたクライアントユーザーの権限でファイルサーバーにアクセスしたい」という高度な要件は、資格情報の使い回しではなく偽装(impersonation)の領域です。公式ドキュメントもサービスが資格情報を抱え込むより偽装を推奨しています。2 偽装の正しい書き方と、リモート資源で追加の考慮が必要になる点は「Windowsの偽装トークンを正しく扱う」を参照してください。

自環境を診断する ── まず叩くコマンド

ここまでの話は、症状が出ている環境で状態を確認できて初めて実務になります。切り分けの起点は、そのプロセスが誰として動いていて、どの接続を持っているかです。次の3つを、症状が出ているのと同じ実行コンテキストで叩いてください。

コマンド 分かること 見るポイント
whoami いま自分が誰として動いているか(ドメイン名\ユーザー名 の形式で表示される) 想定した実行アカウントと一致しているか。サービスなら第3章の表のどの行に当たるか
net use(引数なし) そのログオンセッションが持っているネットワーク接続の一覧22 見えないはずのZ:が一覧にあるか。無ければ「そのセッションには存在しない」が確定する
net use \\fileserver01\share 指定した接続の状態22 接続自体が確立できていないのか、確立できたうえで権限で弾かれているのか

肝心なのは同じコンテキストで実行することです。自分のデスクトップで net use を叩いても、サービスが持っている接続の話にはなりません。サービスの実行アカウントで確認したいときは、タスクスケジューラに同じアカウント・同じ特権設定で cmd /c "whoami > C:\temp\who.txt & net use >> C:\temp\who.txt" のようなタスクを一時的に登録し、その出力ファイルを見るのが確実です。

エラー1219を手元で再現する

1219は、説明を読むより一度自分で出したほうが早く腹落ちします。ドメイン参加した端末で、同じファイルサーバー上の2つの共有に別々の資格情報で接続してみてください。

:: 1) 自分のアカウントで1つ目の共有に接続する(パスワードは * でプロンプト入力)
net use \\fileserver01\share1 * /user:CONTOSO\tanaka

:: 2) 同じサーバーの別の共有に、別のアカウントで接続しようとする
net use \\fileserver01\share2 * /user:CONTOSO\svc-file
::    → ここで上に引用したエラー 1219 が返り、接続できない

:: 後片付け:このセッションのネットワーク接続をすべて切る
net use * /delete

ポイントは、共有が別でもサーバーが同じなら衝突することです。1つ目が share1、2つ目が share2 でも関係ありません。制約はサーバー単位だからです。逆に、1つ目の接続を net use \\fileserver01\share1 /delete で切ってから2つ目を張れば成功します ── つまり順番によっては通ってしまうため、開発中は再現せず本番で初めて出る、という嫌な出方をします。回避策としてIPアドレスや別名を使う場合は、直前で触れたSPNの前提を忘れないでください。1021

5. 「遅い・切れる・いないことがある」を前提に設計する

ローカルディスクと同じ感覚で書いたコードは、共有フォルダ相手では必ずどこかで事故ります。前提にすべき現実は3つです。

第一に、接続は切れるのが正常です。アイドル状態の接続は、サーバー資源の浪費を防ぐため既定で15分のタイムアウト後に切断されます。エクスプローラーのネットワークドライブに赤い×が付くお馴染みの現象がこれで、次にアクセスすれば速やかに再接続されます。12 つまり「たまにしかアクセスしない業務アプリが、アクセスのたびに一瞬待たされる」「監視ツールが『切断された!』と騒ぐが実害はない」のはどちらも仕様どおりの動きです。接続の存在を監視するのではなく、実際のI/Oが成功するかで判断します。

このタイムアウトは変更できます。ただしサーバー側とクライアント側の2か所にタイマーがあり、短いほうが勝つ点に注意してください。12

どこ 設定 内容
サーバー側(コマンド) net config server /autodisconnect:<分> アイドル切断までの分数。最大値は65,535。0 を指定しても無効化にはならず、数秒のアイドルで切断されるようになる点が罠
サーバー側(コマンド) net config server /autodisconnect:-1 autodisconnect機能そのものを無効にする
サーバー側(レジストリ) HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parametersautodisconnect(REG_DWORD) タイムアウトの変更のみ。この方法では機能を無効化できない
クライアント側(レジストリ) HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parametersKeepConn(REG_DWORD、1〜65535秒) クライアント側のアイドル保持時間。既定は600秒(10分)

見落としやすいのは最後の行です。クライアント側の既定値は10分で、サーバー側の既定の15分より短いため、サーバー側だけを延ばしても切断の挙動は変わりません。セッションは autodisconnectKeepConn短いほうの値で切断されるからです。12

とはいえ、これらを変更するのは第一選択ではありません。切断は仕様どおりの動作で、次のアクセスで再接続されるため実害がないのが通常です。値をいじるのは、切断のたびに落ちる古いアプリを抱えていて手が出せない、といった事情があるときに限り、しかも他のシステムにも影響する設定であることを踏まえて、サーバー管理者と合意のうえで行ってください。アプリ側は「切れる前提でリトライする」に寄せるのが本筋です。

第二に、エラーの出方が不親切です。File.Exists は、パスが不正でも、権限が足りなくても、ディスク障害でも、例外を出さずに false を返します。13 ローカルでは「falseなら無い」でほぼ困りませんが、共有相手では「ファイルが無い」と「サーバーに届かない/権限が無い」がすべて false に潰されるため、Existsで分岐して業務判断をするコードは、ネットワーク障害時に『対象なし』として正常終了するという嫌な壊れ方をします。存在確認を挟まず開きにいって例外で区別する方が、共有相手では診断しやすい設計です。

第三に、相手はまだいないことがあります。マシン起動直後はネットワークの準備よりサービスの起動が先行することがありますし、ファイルサーバー側が再起動中かもしれません。持続的接続(persistent connection)はユーザーのログオン時に復元される仕組みなので23、ログオンを経ないサービスの世界では「起動したら共有が見える」ことに保証はありません。起動時に一度だけ疎通確認して失敗したら終了、ではなく、リトライしながら待つのが正しい振る舞いです。

この3つを織り込むと、書き込み側の骨格はこうなります。

// 一時的なネットワークエラーはリトライ、業務エラーは即時失敗させる
private static async Task WriteToShareAsync(string finalPath, byte[] content, CancellationToken ct)
{
    var dir = Path.GetDirectoryName(finalPath)!;
    var tempPath = Path.Combine(dir, $"~{Guid.NewGuid():N}.tmp");

    try
    {
        for (var attempt = 1; ; attempt++)
        {
            try
            {
                await File.WriteAllBytesAsync(tempPath, content, ct);
                File.Move(tempPath, finalPath); // 同一ディレクトリ内のrenameで「完成」を公開
                return;
            }
            catch (IOException ex) when (attempt < 5 && IsRetryable(ex))
            {
                // 一時的なネットワーク障害だけを指数バックオフで再試行(上限つき)
                _logger.LogWarning(ex, "共有への書き込み失敗({Attempt}回目)。再試行します", attempt);
                await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)), ct);
            }
        }
    }
    catch
    {
        // 諦めて例外を伝播させるときは、一時ファイルをベストエフォートで掃除する
        try { File.Delete(tempPath); } catch { /* 掃除の失敗は握りつぶす */ }
        throw;
    }
}

// IOExceptionは「ネットワーク切断」も「移動先に同名ファイルあり」も「ディスク満杯」も同じ型で飛んでくる。
// HResultの下位16bit(Win32エラーコード)で、再試行に意味がある一時的な障害だけを選ぶ
private static bool IsRetryable(IOException ex)
{
    var win32 = ex.HResult & 0xFFFF;
    return win32 is 53   // ERROR_BAD_NETPATH: ネットワークパスが見つからない
              or 59   // ERROR_UNEXP_NET_ERR: 予期しないネットワークエラー
              or 64   // ERROR_NETNAME_DELETED: ネットワーク名が利用できなくなった
              or 121; // ERROR_SEM_TIMEOUT: タイムアウト(いわゆるセマフォタイムアウト)
}

「IOExceptionならリトライ」と雑に書かないことも重要です。移動先に同名ファイルがある、パスが長すぎる、ディスクが満杯といった何度やっても結果が変わらない失敗も同じIOExceptionで届くため、例外の型だけで判定すると、恒久的なエラーを5回リトライして無駄にバックオフで待つことになります。上の例のように、Win32エラーコード(53/59/64/121など、共有アクセスの切断・タイムアウト系24)で「再試行に意味がある失敗」だけを選別してください。実環境のログで観測したコードを足していく運用が現実的です。

ポイントは、リトライを付けることそのものより、リトライしても安全な受け渡しプロトコル(temp -> rename、idempotency)とセットにすることです。書き込み途中で切断されたら中途半端なファイルが残ります。final名は「閉じてからのrename」でしか現れない約束にしておけば、受信側が生焼けのファイルを読む事故を防げます。なお、プロセスのクラッシュや電源断ではコード内の掃除自体が走らないので、受け渡しフォルダには「~*.tmp のうち一定時間更新のないものを削除する」定期清掃も併せて用意しておくと、ゴミの蓄積で詰まりません。この受け渡し設計の全体像は「ファイル連携の排他制御の基礎知識」にまとめています。

もう一つ、ネットワーク相手特有の注意があります。「失敗した」という結果は、本当に失敗したことを保証しません。サーバー側でrenameが完了した直後に接続が切れると、クライアントには例外が返るのに、final名のファイルはすでに公開されている、という状態が起こり得ます。このまま何も考えずに再試行すると、「移動先にすでに同名ファイルがある」エラーで詰まるか、受信側がすでに1つ目を取り込んでいた場合には同じデータを二重に公開してしまいます。対策は、rename段の失敗を再試行する前に移動先の状態を確認して突き合わせることです。final名に処理ID(伝票番号や実行GUID)を含めておけば、「同じIDのfinalファイルがすでに存在する=前回のrenameは実は成功していた」と判定して成功扱いで抜けられますし、受信側もIDの重複で二重取り込みを弾けます。

6. SMB越しの排他制御とFileSystemWatcherの信頼性

6.1. ロックへの過信は禁物

共有フォルダは複数のクライアントから同時に触られます。FileShare.None で開けば開いている間の排他はSMB越しでも機能しますが、「ロックが取れたら安全」に寄りかかった設計は、切断でハンドルが失われたとき、ロックを取らない相手(手作業のコピー、他システム)が混ざったときに崩れます。排他の本体はOSのロックではなく、temp -> rename・原子的claim(incomingからprocessingへのrename勝者だけが処理する)・idempotencyという受け渡しプロトコル側に置くべきです。考え方の詳細は上掲の排他制御の記事に譲ります。

6.2. FileSystemWatcherをリモート共有で使うときの現実

FileSystemWatcher は、ローカルだけでなくネットワークドライブやリモートコンピューター上のファイル監視をサポートすると公式に明記されています。14 使うこと自体は正当です。ただし信頼性の前提が2つあります。

  • 通知はバッファ経由であり、あふれれば取りこぼします。変更が短時間に集中するとバッファサイズを超えた分のイベントは失われます。14
  • ネットワーク越しの監視では InternalBufferSize の上限が64KBに制限されます。ローカルより「盛れない」制約が明文化されています。14

さらに、共有の向こう側でサーバーの再起動や切断が起きたとき、監視が黙って死んでいるだけで通知が来ない、という症状は不具合調査の現場で繰り返し見てきました。リモート共有のFileSystemWatcherは「気づくのを早くするためのヒント」と割り切り、起動時・エラー時・定期のフルスキャン(ポーリング)を真実の源にするのが実務の結論です。イベントの重複・順序の崩れへの対処も含めた設計パターンは「FileSystemWatcher実務ガイド」で詳述しています。

7. 実務の定石(判断表)

ここまでの内容を、設計時に迷う論点ごとの判断表にまとめます。

論点 選択肢 判断の目安
パスの持ち方 ドライブ文字 / UNCパス アプリが扱うパスは常にUNC。ドライブ文字はユーザーの画面上の便宜と割り切る2
共有への書き込み 直書き / temp -> rename 直書きは「途中のファイルを読まれない」保証がない。final名=完成の約束が基本
新着ファイルの検知 FileSystemWatcher単独 / ポーリング / 併用 リモート共有では取りこぼし前提。数分間隔で許されるならポーリングだけの方が単純で堅い。即時性が必要なら併用14
サービスの実行アカウント LocalSystem / ドメインアカウント / gMSA 共有アクセスがあるならドメインアカウントかgMSA。gMSAが使える環境ならパスワード運用ごと消せる1
資格情報が別に必要なとき net useをコードで叩く / WNetAddConnection2 / cmdkey事前登録 サービス内のnet useは非推奨。同一サーバーへの複数資格情報は1219で詰むので、アカウント集約かDNSエイリアスで設計段階から回避210
クライアント多数からの直アクセス 各端末がUNC直 / 中間サービス(API)経由 端末台数×資格情報×同時アクセスが管理しきれなくなったら、共有を触るのは1つのサービスに集約し、クライアントはAPIで話す構成に寄せる

最後の行は補足しておきます。共有フォルダ連携は手軽ですが、アクセス元が増えるほど「誰がどの権限で」「誰と誰が競合するか」の管理が指数的に難しくなります。ある規模を超えたら、ファイルサーバーに触るプロセスをWindowsサービス1本に集約し、各クライアントとはHTTPやgRPCで会話する。共有フォルダを「システム間のインターフェース」から「そのサービスの内部実装」に格下げするのが、長期的にもっとも保守しやすい形です。

8. まとめ

  • ドライブ文字はログオンセッション単位の記号にすぎません。別ユーザー・昇格プロセス・サービスから見えないのは仕様であり、アプリはUNCパスで書くのが正道です。EnableLinkedConnections は非サポートの回避策です。
  • サービスからの共有アクセスはUNC必須。誰として認証されるかは実行アカウントで決まり、LocalSystem/NetworkServiceはコンピューター資格情報、LocalServiceは匿名です。実務はドメインアカウントかgMSAに共有側の権限を与えます。
  • 同一サーバーへの複数資格情報の同時接続はエラー1219で失敗します(仕様)。アカウント集約かDNSエイリアスで設計段階から回避します。
  • 共有は「遅い・切れる・いないことがある」が正常系。アイドル切断(既定15分)は異常ではなく、File.Exists のfalseはネットワーク障害と区別できません。リトライとtemp -> rename、idempotencyをセットで入れます。
  • FileSystemWatcherはリモート監視をサポートしますが、バッファあふれによる取りこぼしと64KB上限があるため、フルスキャンの併用が定石です。
  • 迷ったら第7章の判断表へ。規模が育ったら、共有を触るプロセスを中間サービスに集約する構成も検討してください。

関連記事

関連する相談領域

合同会社小村ソフトでは、共有フォルダを介したファイル連携システムの設計・実装、Windowsサービス化に伴うアクセス権・認証まわりの構成検討、「サービスにしたら共有が見えない」「特定環境でだけ失敗する」といった不具合の調査を扱っています。

参考リンク

  1. Microsoft Learn, Group Managed Service Accounts overview. gMSAが自動パスワード管理とSPN管理の簡素化を提供するドメインアカウントであり、パスワード管理をWindows OSに任せられることについて。  2 3 4 5 6 7 8

  2. Microsoft Learn, Services and Redirected Drives. ドライブ文字がシステムグローバルではなくログオンセッションごとに割り当てられること、サービスは他セッションのドライブ文字にアクセスできずUNC名を使うべきこと、サービス内でのnet use・WNet関数によるドライブマップが非推奨である理由(資格情報の漏えい、サービス間の干渉など)、ユーザーアカウントで構成したサービスにも新しいログオンセッションが作られること、資格情報の抱え込みよりクライアント偽装が推奨されることについて。  2 3 4 5 6 7 8 9 10 11 12

  3. Microsoft Learn, Mapped drives are not available from an elevated prompt when UAC is configured to Prompt for credentials. UAC有効時にリンクされた2つのログオンセッションが作られること、ドライブマップの実体がログオンセッション固有のシンボリックリンクオブジェクト(DosDevices)でありセッション間で共有されないこと、EnableLinkedConnectionsが両セッションへのシンボリックリンク書き込みを強制することについて。  2 3

  4. Microsoft Learn, Folder Redirection fails to apply when redirected to mapped drive letter, instead of UNC path. 管理者ログオン時にLSAが2つのアクセストークンを作り標準トークンでドライブがマップされること、EnableLinkedConnectionsレジストリ値の設定手順と「システムを安全でなくする可能性があり、Microsoftはサポートしない」という警告、ドライブ文字ではなくUNCパスの使用が常に推奨されることについて。  2 3

  5. Microsoft Learn, LocalSystem Account. LocalSystemがローカルで広範な特権を持ち、ネットワーク上ではコンピューターの資格情報をリモートサーバーに提示することについて。  2 3

  6. Microsoft Learn, NetworkService Account. NetworkServiceがローカルでは最小限の特権を持ち、ネットワーク上ではコンピューターの資格情報をリモートサーバーに提示することについて。  2 3

  7. Microsoft Learn, LocalService Account. LocalServiceがネットワーク上では匿名資格情報を提示することについて。  2

  8. Microsoft Learn, About Service Logon Accounts. サービスのログオンアカウントが実行時のセキュリティコンテキストを決めること、ローカルユーザーアカウントのセキュリティコンテキストで動くサービスがネットワーク資源にアクセスできないことについて。  2

  9. Microsoft Learn, Create a Key Distribution Service (KDS) Root Key. ドメインコントローラーがgMSAのパスワード生成にKDSルートキーを必要とすること、Add-KdsRootKey -EffectiveImmediately で作成すること、作成から最大10時間はすべてのドメインコントローラーのAD複製が収束するまでgMSAを作成できないこと(全DCがgMSA要求に応えられるようになる前のパスワード生成を防ぐ安全策)、gMSAの管理コマンドの実行に64ビットアーキテクチャが必要であることについて。  2 3 4

  10. Microsoft Learn, The network folder specified is currently mapped using a different user name and password error. 同一サーバーへ異なる資格情報で複数接続しようとしたときのエラーがby design(仕様)であること、回避策がIPアドレス接続または別のDNSエイリアスの作成であることについて。  2 3 4

  11. Microsoft Learn, System Error Codes (1000-1299). エラー1219(ERROR_SESSION_CREDENTIAL_CONFLICT)の定義とメッセージについて。  2

  12. Microsoft Learn, Mapped drive connection to network share may be lost. アイドル接続が既定で15分のタイムアウト後に切断されること(autodisconnect)、エクスプローラーのドライブアイコンに赤い×が表示されるがアクセスすれば速やかに再接続されること、net config server /autodisconnect:<分> でタイムアウトを変更でき最大値が65,535であること、0 を指定しても機能は無効化されず数秒のアイドルで切断されるようになること、-1 で機能を無効化できること、サーバー側レジストリ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parametersautodisconnect ではタイムアウトの変更のみ可能で無効化はできないこと、クライアント側レジストリ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parametersKeepConn(REG_DWORD、1〜65535秒、既定600秒)があり、セッションは autodisconnect と KeepConn の短いほうの値で切断されることについて。  2 3 4

  13. Microsoft Learn, File.Exists(String) Method. 読み取り権限がない場合に例外を出さずfalseを返すこと、存在判定中に何らかのエラーが発生した場合(無効なパス、ディスク障害、権限不足など)もfalseを返すことについて。  2

  14. Microsoft Learn, FileSystemWatcher Class. ローカルコンピューター・ネットワークドライブ・リモートコンピューター上のファイル監視をサポートすること、バッファサイズ超過時にイベントを取りこぼしうること、ネットワーク越しの監視ではInternalBufferSizeの最大値が64KBであることについて。  2 3 4 5

  15. Microsoft Learn, WNet Functions. WNetGetUniversalNameがドライブベースのパスからユニバーサル(UNC)形式の名前を取得する関数であることについて。 

  16. Microsoft Learn, Secure group managed service accounts. gMSAのパスワードが240バイトのランダム生成であり、OSが30日ごとに自動変更するため管理者によるパスワード変更の計画やサービス停止が不要になることについて。  2

  17. Microsoft Learn, Service Accounts and BITS. LocalSystem/NetworkServiceのネットワーク認証がコンピューター資格情報、LocalServiceが匿名資格情報で行われること、ACLがユーザーアカウントに限定されている場合にアクセス拒否となること、システムアカウントがマップドドライブを使うべきでないことについて。 

  18. Microsoft Learn, cmdkey. cmdkeyコマンドで保存済みユーザー名とパスワード(資格情報)を作成・一覧・削除できることについて。 

  19. Microsoft Learn, Credentials processes in Windows authentication. 資格情報マネージャーが資格情報をWindows資格情報コンテナーに保存し、次回以降の認証時に自動的に提示することについて。 

  20. Microsoft Learn, Client Access to Network Resources. サーバープロセスがネットワーク資源にアクセスする戦略として、クライアントの資格情報を指定したWNetAddConnection2による接続確立が挙げられていることについて。 

  21. Microsoft Learn, SMB file server share access is unsuccessful through DNS CNAME alias. CNAME経由のSMBアクセスが失敗する原因の一つがエイリアスに対するSPN未登録であること、DNSのCNAMEではなくnetdom computernameコマンドで別名を定義する方法が案内されていることについて。  2

  22. Microsoft Learn, Net use. パラメーターなしで実行するとネットワーク接続の一覧を取得すること、net use <デバイス名> で特定の接続の情報を表示できること、パスワードに * を指定するとプロンプトで入力できること、/user で別のユーザー名を指定できること、/delete* を指定するとすべてのネットワーク接続が解除されることについて。  2

  23. Microsoft Learn, Windows Networking Operations. 持続的接続(persistent connection)がユーザーのログオン時にシステムによって自動復元されるネットワーク接続であることについて。 

  24. Microsoft Learn, System Error Codes (0-499). ERROR_BAD_NETPATH(53)、ERROR_UNEXP_NET_ERR(59)、ERROR_NETNAME_DELETED(64)、ERROR_SEM_TIMEOUT(121)の各定義について。 

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

Windowsサービスからネットワークドライブ(Z:)にアクセスできないのはなぜですか?
ドライブ文字がシステム全体のものではなく、ログオンセッション単位のものだからです。ユーザーがエクスプローラーでマップしたZ:は、そのユーザーのログオンセッションに属する記号でしかなく、別のログオンセッションで動くサービスからは見えません。サービスがユーザーアカウントで動く場合でも、システムはサービス用に新しいログオンセッションを作るため、同じアカウントでもデスクトップ側のマップは引き継がれません。サービスからは\\server\shareのUNCパスでアクセスするのが正解です。
LocalSystemで動くサービスから共有フォルダにアクセスするには?
LocalSystemはネットワーク上ではコンピューターの資格情報として認証されます。ドメイン環境であれば、共有側(共有のアクセス許可とNTFSのACL)にそのマシンのコンピューターアカウント(DOMAIN\MACHINE$)への権限を付与すればアクセスできます。ただしマシンを入れ替えると権限設定がやり直しになるなど運用しづらいため、実務ではサービスの実行アカウントをドメインアカウントかgMSA(グループ管理サービスアカウント)にして、そのアカウントに共有側の権限を与える構成を推奨します。
共有フォルダ上のファイルをFileSystemWatcherで監視してよいですか?
使えますが、単独では信頼しないでください。FileSystemWatcherはネットワークドライブやリモートコンピューター上の監視をサポートしますが、変更通知はバッファ経由で届くため、通知が集中するとバッファがあふれてイベントを取りこぼします。しかもネットワーク越しの監視ではバッファの上限が64KBに制限されます。通知は「再スキャンのきっかけ」として扱い、起動時・エラー時・定期のフルスキャン(ポーリング)を必ず併用するのが定石です。
ネットワーク切断に強いファイル連携にするにはどうすればよいですか?
「共有は遅い・切れる・いないことがある」を正常系として設計します。具体的には、書き込みは一時ファイル名で行いclose後にリネームして公開する(temp -> rename)、読み書きはリトライで包み、一時的なネットワークエラーと業務エラーを区別して扱います。File.Existsはアクセスできない場合もfalseを返すため「ファイルが無い」と「サーバーに届かない」を区別できない点に注意し、再処理しても壊れないidempotencyな処理にしておくことが最後の砦になります。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る