2014年10月20日月曜日

Windowsで消せないファイルをバッチで削除してみた


概要


前回、ProcessExplorerでhandleをクローズすることで ファイルを削除したが、
Oracleのトレースログが忘れた頃に同じ現象を起こしてくれて、手動で削除するのはかなり面倒。
なので、バッチ化できないかトライします。


ちなみに、デフォルトで入っている「openfiles」コマンド でも「/Disconnect」オプションが
存在するので試してみましたが結果としては、ダメでした。(Win7のPC)

準備

今回は「handle.exe」 を使って削除します。


まずは使用方法から。

使用方法: handle [[-a] [-u] | [-c <ハンドル> [-l] [-y]] | [-s]] [-p <プロセス名>|] [<名前>]

オプション説明
オプション 説明
-a ファイルを参照しているハンドルだけでなく、すべての種類のハンドルに関する情報をダンプします。
-c 指定のハンドルを閉じます。プロセスの指定も必要です。
-l ページ ファイルを使用するセクションのサイズをダンプします。
-y ハンドルを閉じることについて確認のメッセージを表示しません。
-s 開いている各種類のハンドルの数を出力します。
-u ハンドルの検索時に、そのハンドルを所有しているユーザー名を表示します。
-p このパラメーターを使用すると、システム内のすべてのハンドルを確認するのではなく、名前が指定した文字列で始まるプロセスに限定して、 ハン ドルをスキャンできます。





オプション無しで実行



E:\wk>Handle.exe

Handle v4.0
Copyright (C) 1997-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

------------------------------------------
smss.exe pid: 340 NT AUTHORITY\SYSTEM
    4: File  (RW-)   C:\Windows
------------------------------------------
csrss.exe pid: 584 NT AUTHORITY\SYSTEM
    8: File  (RW-)   C:\Windows\System32
   28: Section       \Windows\SharedSection


「---」で囲まれているのが、1つのプロセス内で実行されている内容で、
先頭行には「イメージ名」「pid」「ユーザ名」
2行目以降は「ハンドル(ID)」「タイプ」「オープンモード」「オブジェクト」が表示される。



対象のファイルを指定して実行(フォルダでも可)

dle.exe


E:\wk>Handle.exe E:\wk\close_test.txt

Handle v4.0
Copyright (C) 1997-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

cscript.exe        pid: 6112   type: File           1AC: E:\wk\close_test.txt




表示形式が変わって「イメージ名」「pid」「タイプ」「ハンドル(ID)」:「オブジェクト」を1行で表示してくれる。



切断:
意外と悩んでしまったが、-c、-pは一緒にしていしないとエラーとなる。



e:\wk>Handle.exe  -c 1AC -y -p
6112 E:\wk\close_test.txt

Handle v4.0
Copyright (C) 1997-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

  1AC: File  (R--)   E:\wk\close_test.txt

Handle closed.



「Handle closed」と表示されたら完了



状態確認:



E:\wk>Handle.exe E:\wk\close_test.txt

Handle v4.0
Copyright (C) 1997-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

No matching handles found.



これで対象ファイルが解放される。






スクリプト作成

以下のスクリプトを作成する。
なお、テストで何回も実行したいので、テスト用のスクリプトも準備します。


hclose.bat
ハンドルクローズ用スクリプトで、対象ファイルをパラメータとして渡す。

@echo off

rem : 対象ファイルをフルパスでパラメータとして渡す
set closefile=%1

rem : Handle.exeのパスを指定する。(set PATHでも可)
set hanexe=E:\wk\Handle.exe

rem : -------------------------------------------
rem : メイン処理
rem : -------------------------------------------
for /F "tokens=1-7 skip=5 delims= " %%A IN  ('%hanexe% %closefile%') do (
call :sub %%F %%C %%G
)

exit /b


rem : -------------------------------------------
rem : for文の中で変数の変換ができないので
rem : サブルーチンとしてHandleのクローズ処理を実行
rem : -------------------------------------------
:sub

rem : 末尾の":"を削除
set hid=%1
set hid=%hid::=%

rem : 対象が存在しない場合は処理を抜ける
if "%1" == "" goto endpg
if "%2" == "" goto endpg
if "%3" == "" goto endpg


echo ■■■クローズする対象を表示■■■
%hanexe% %3

echo ■■■ハンドルクローズ■■■
%hanexe% -c %hid% -y -p %2 %3

rem : エラーハンドリングを追加するならここへ
rem : if not errorlevel 0 ~

exit /b

rem : -------------------------------------------
rem : 対象が存在しない場合、echoで表示してクローズ
rem : -------------------------------------------
:endpg
echo 対象無し

exit /b




handle_test.vbs
テスト用スクリプト。パラメータで対象ファイルをフルパス指定する。

Dim fso, ts
Const ForWriting = 2
Set objParm = Wscript.Arguments

Set fso = WScript.CreateObject("Scripting.FileSystemObject")
Set ts = fso.OpenTextFile(objParm(0), 8)

Do
WScript.Sleep(10000)
Loop

ts.Close

set fso = Nothing
set ts = Nothing







スクリプト確認

作成したスクリプト、Handle.exeをE:\wk\に保存しました。
今回、確認で使用するファイルも準備しておきます。(close_test.txt)


E:\WK\
  close_test.txt
  Handle.exe
  handle_test.vbs
  hclose.bat


テスト用に作成した「handle_test.vbs」でファイルにロックを掛け、本当にクローズできるかチェックする。
startコマンドを実行しているので、別ウィンドウが立ち上がりますが、テスト中は閉じないでください。
なお、ファイルのステータスを監視してないので、ハンドルのクローズを行った後は×ボタンで閉じてください。


結果

e:\wk>start cscript //nologo handle_test.vbs E:\wk\close_test.txt

e:\wk>
e:\wk>hclose.bat E:\wk\close_test.txt
■■■クローズする対象を表示■■■

Handle v4.0
Copyright (C) 1997-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

cscript.exe pid: 2328 type: File 1AC: E:\wk\close_test.txt
■■■ハンドルクローズ■■■

Handle v4.0
Copyright (C) 1997-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

1AC: File (R--) E:\wk\close_test.txt

Handle closed.



これで解除が完了しました。


ファイルがロックされてないタイミングだと、
「対象無し」と表示して終わる仕組みになっています。


e:\wk>hclose.bat E:\wk\close_test.txt
対象無し






Handleのヘルプにも記載がありますが、システムが不安定になる場合もありますので
くれぐれも気を付けて、自己責任で実行ください。



0 件のコメント:

コメントを投稿