2014年8月30日土曜日

[Windows] ファイルを開いているプロセスを見つける

「*** は編集のためロックされています。」とか
「別のプログラムがこのフォルダーまたはファイルを開いているので、操作を完了できません。フォルダーまたはファイルを閉じてから再実行してください。」

とのエラーメッセージが表示されるものの、一体何がファイルを開いているのか分からない!そこでファイルを開いているプロセスを探す方法です。


### リモートから開いている共有フォルダのファイルを探す ###

ネットワーク端末から該当する PC のファイルにアクセスされている場合の対処について。

■ コマンドで作業する

ファイルの一覧を表示するには、このコマンドを実行します。
> net file
アクセスされてるファイルが一覧表示されます。他に「一覧にエントリが存在しません。」と表示されればファイルは開かれていません。

ファイルを閉じるには、このコマンドを実行します。
> net file ID(※注) /Close
※注:ID は開いているファイルの ID を記述する

■ 画面で作業する

コントロール パネル > システムとセキュリティ > 管理ツール > コンピューターの管理 と辿って
ツリーの「システムツール > 共有フォルダー > セッション」もしくは「開いているファイル」を開く。
閉じたい項目を右クリックして「セッションを閉じる」もしくは「開いているファイルを閉じる」を選択する。


### ローカルで開いているファイルを探す ###

ローカルのプロセスがファイルをロックしている場合の対処について。

■ タスクマネージャ から探す

Windows タスクマネージャ を開いて、「プロセス」タブからプロセスの「コマンド ライン」を確認する。
コマンドラインはデフォルトでは表示されていないので、表示列を追加する必要がある。
(手順)「表示」メニュー > 列の選択 > 「コマンド ライン」をチェック

ドキュメントであればコマンドの引数として起動されている場合が多いので、これで多くは確認することができる。

■ TASKLIST コマンドで探す

タスクマネージャで多くのプロセスを目で追うのが面倒であれば、コマンドでファイル名(の一部)を探せば早い。これはコマンドライン引数でなく、プロセスのウィンドウタイトルを検索することになるのだが、ドキュメントであればファイル名がウィンドウタイトルに使われる傾向が高いことを利用する。このためアプリケーションのデータファイルだと効果が無いが、そういう場合はアプリとファイルの繋がりは特定できるので、こうやって探す必要も無いのでは...?

> tasklist /V | findstr (ファイル名の一部)

プロセスを停止するには、
> taskkill /PID (プロセスID) /T

■ OPENFILES コマンドで探す

これはローカルで開いているファイルをリストアップできるが、スイッチを「有効」に切り替えてシステムの再起動が必要になる。これはフラグを有効にすると、パフォーマンスに負荷がかかるためにデフォルトでは無効になっているのだが、再起動するならロックの調査する必要はないですよね...
コマンドライン引数でないファイルのOpenについては、この方法で見つけることができます。

> openfiles /Local ON
(再起動が必要)
> openfiles /Query | findstr (フォルダ名やファイル名の一部)

■ System.Diagnostics.Process クラスで探す

Process.StartInfo プロパティ(ProcessStartInfo クラス)のうち Arguments プロパティでコマンド ライン引数を確認できるが、これは下記のように条件が厳しくてほとんど使えない。

http://msdn.microsoft.com/ja-jp/library/system.diagnostics.process.startinfo.aspx
プロセスの開始に Start メソッドを使用しなかった場合、StartInfo プロパティはプロセス開始に使用されたパラメーターを反映しません。

■ Windows PowerShell の Get-Process コマンドで探す

実はこの出力は上記の System.Diagnostics.Process クラスになるので、同じ理由で使えない...

(例)Acrobat Reader を検索
PS> Get-Process | Where-Object {$_.ProcessName -match 'AcroRd'}

Get-Process
http://technet.microsoft.com/ja-jp/library/hh849832.aspx

Get-Process コマンドレットの使用
http://technet.microsoft.com/ja-jp/library/ee176855.aspx

■ WMI で探す (コマンド)

WMI(Windows Management Instrumentation)を使って探す。ただし PowerShell のほうが柔軟に操作できるので、次に挙げるほうを選択したほうが良い。

> wmic PROCESS where "CommandLine like '%SampleName ※注%'" get /format:list | findstr /R "CommandLine ProcessId"

※注:フォルダ名やファイル名の一部を記述

Windows Management Instrumentation コマンド ライン
http://msdn.microsoft.com/ja-jp/library/cc784189.aspx

WMIC のヒント集
http://msdn.microsoft.com/ja-jp/library/cc758713.aspx

WMIC の動詞
http://msdn.microsoft.com/ja-jp/library/cc784966.aspx

WMIC で形式を作成および編集する
http://msdn.microsoft.com/ja-jp/library/cc757287.aspx

wmic
http://msdn.microsoft.com/ja-jp/library/aa394531.aspx

■ WMI で探す (Windows PowerShell)

wmic コマンドの PowerShell 版です。

PS> Get-WmiObject -Class Win32_Process | Where-Object {$_.CommandLine -match 'フォルダ名やファイル名の一部'} | Format-Table Caption,CommandLine,ProcessId

Get-WmiObject
http://technet.microsoft.com/ja-jp/library/hh849824.aspx

Win32_Process class
http://msdn.microsoft.com/ja-jp/library/aa394372.aspx

■ 外部のツールで探す

外部製品のプロセスモニタ ソフト等を使って、ファイルのOpenについての操作を探す。ただしファイルのOpenだけでも相当数出力されるので上手くフィルタリングしないと追えません。
これだと、あらゆる調査が可能です。

Process Monitor
http://technet.microsoft.com/ja-jp/sysinternals/bb896645.aspx