止まらない自動化のために。FSOとWMIを連携させ、ストレージの「不機嫌」を事前に察知するプロの技
こんにちは。自動化の世界へようこそ。
「マクロの記録」や、ネットで見つけた「ファイルをコピーするだけのコード」を動かして、一通りの目的を果たせたとき、あなたはきっと小さな達成感を感じたはずです。でも、もしあなたが「エンジニア」として、そのコードを現場の重要な業務ラインに投入しようとしているのなら、一度立ち止まって考えてみてください。
「もし、書き込み先のディスクが壊れかけていたら?」
「もし、USBメモリが書き込み禁止状態だったら?」
単純なコードは、エラーが起きた瞬間に「無慈悲に停止」します。あるいは、中途半端に書き込みを行ってしまい、ファイルを破損させてしまうことさえあります。
今日は、そんな「初学者が陥る罠」を回避し、プロフェッショナルが実践する「守りの自動化(Defensive Programming)」についてお話しします。FileSystemObject(FSO)という「手」と、WMIという「目」を組み合わせることで、ストレージの状態を事前に監査し、安全にファイルを扱う方法をマスターしましょう。
ここをクリアすれば、あなたのVBScriptは「ただ動くもの」から「信頼されるシステム」へと進化しますよ。
1. 二つの道具の役割を知る:FSO(手)とWMI(目)
高度な自動化を実現するには、役割の異なる二つのオブジェクトを使い分ける必要があります。
FileSystemObject (FSO) :「実行する手」
FSOは、ファイルを作ったり、コピーしたり、フォルダを消したりするための道具です。
- 得意なこと: ファイルの作成、移動、削除、コピー、存在確認。
- 弱点: 「その場所が今、物理的に書き込める状態か?」という、OSの深いレベルの健康状態までは知りません。
WMI (Windows Management Instrumentation) :「監視する目」
WMIは、Windows OSそのものの情報を覗き見るための窓口です。
- 得意なこと: CPUの温度、メモリの使用量、そして「ディスク(ドライブ)の属性や状態」の取得。
- 役割: ファイルを操作する「前」に、その場所が安全かどうかをチェックします。
「目(WMI)で周囲を確認してから、手(FSO)を動かす」。これがプロの作法です。
2. 実践:ディスクの状態を監査する「安全装置」の設計
では、具体的なコードを見ていきましょう。
今回は、「指定したドライブが書き込み可能か、そして異常な状態(読み取り専用など)ではないか」をチェックしてから、ファイルを安全に退避(コピー)するスクリプトを作成します。
' ==========================================================================
' 【プロフェッショナル仕様】安全なファイル退避スクリプト
' 概要: WMIでドライブの状態を監査し、安全が確認できた場合のみFSOで操作を行う
' ==========================================================================
Option Explicit
' 定数定義(マジックナンバーを避け、可読性を高める)
Const DRIVE_TYPE_FIXED = 3 ' ローカルハードディスク
Const DRIVE_TYPE_REMOVABLE = 2 ' リムーバブルディスク(USBメモリ等)
Dim targetDrive, sourceFile, destFolder
targetDrive = "C:" ' 監査対象のドライブ
sourceFile = "C:\Data\重要書類.txt"
destFolder = "D:\Backup\" ' 退避先(例としてDドライブ)
' --- メイン処理 ---
If IsDiskSafe(targetDrive) Then
MsgBox targetDrive & " は安全です。操作を開始します。", vbInformation, "監査完了"
SafeFileCopy sourceFile, destFolder
Else
MsgBox targetDrive & " に異常、または書き込み禁止状態を検知しました。処理を中断します。", vbCritical, "警告:安全確保"
End If
' ==========================================================================
' 関数: IsDiskSafe
' 目的: WMIを使用して、指定されたドライブが書き込み可能かチェックする
' 戻り値: Boolean (True: 安全, False: 危険)
' ==========================================================================
Function IsDiskSafe(driveLetter)
Dim objWMIService, colDisks, objDisk
Dim isSafe
isSafe = False ' デフォルトは「危険」とみなす(Fail-safe設計)
On Error Resume Next ' WMI接続エラーに備える
' WMIサービスへの接続
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
If Err.Number <> 0 Then
WScript.Echo "WMI接続エラー: " & Err.Description
IsDiskSafe = False
Exit Function
End If
' Win32_LogicalDisk クラスから情報を取得
' DriveLetter プロパティで対象を指定
Set colDisks = objWMIService.ExecQuery _
("Select * from Win32_LogicalDisk Where DeviceID = '" & driveLetter & "'")
For Each objDisk In colDisks
' 1. ドライブが存在するか?
' 2. 書き込み禁止(ReadOnly)ではないか?
' 3. ドライブタイプが適切か? (ここでは固定ディスクまたはリムーバブルを許可)
If Not objDisk.IsReadOnly And _
(objDisk.DriveType = DRIVE_TYPE_FIXED Or objDisk.DriveType = DRIVE_TYPE_REMOVABLE) Then
isSafe = True
End If
Next
On Error GoTo 0 ' エラーハンドリングを元に戻す
IsDiskSafe = isSafe
End Function
' ==========================================================================
' 関数: SafeFileCopy
' 目的: FSOを使用して安全にファイルをコピーする
' ==========================================================================
Sub SafeFileCopy(src, dest)
Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")
On Error Resume Next ' ファイル操作中の予期せぬエラー(セクタエラー等)を捕捉
' コピー実行
objFSO.CopyFile src, dest, True ' Trueは上書き許可
If Err.Number <> 0 Then
' ここでエラーが起きた場合、物理的な書き込み失敗(セクタエラー等)の可能性がある
WScript.Echo "致命的なエラーが発生しました: " & Err.Description, vbCritical
Else
WScript.Echo "ファイルの退避に成功しました。", vbInformation
End If
On Error GoTo 0
Set objFSO = Nothing
End Sub
3. コードの深層:なぜこの書き方をするのか?
このコードには、初学者が卒業すべき「3つのプロの設計思想」が組み込まれています。
① Fail-safe(フェイルセーフ)設計
`isSafe = False` を関数の最初に宣言しています。これは、「もしチェック中に何らかの理由でエラーが起きても、デフォルトでは『危険』と判断する」という考え方です。
「確認に失敗した=安全」と判断してしまうと、壊れたディスクに書き込みに行ってしまうかもしれません。プロは「不明なものは、危険とみなす」のです。
② WMIによる「属性」の監査
`objDisk.IsReadOnly` をチェックしています。
USBメモリの物理スイッチが「Lock」になっていたり、ネットワークドライブが読み取り専用でマウントされていたりする場合、FSOでいきなり書き込もうとすると、プログラムはエラーで止まります。事前にWMIでこれを知ることで、スマートなエラーハンドリングが可能になります。
③ エラーオブジェクトの適切なハンドリング
`On Error Resume Next` は、使い方を誤ると「エラーを無視して進む恐ろしい魔法」になります。
しかし、このコードのように「特定の危険な操作(WMI接続やファイルコピー)の直前」に使い、その直後に `If Err.Number <> 0` でエラーを判定することで、「エラーを無視するのではなく、エラーを捕まえて適切に処理する」という強力な武器に変わります。
4. 陥りやすいエラーと、さらに高みを目指すヒント
この仕組みを運用する上で、以下の点に注意してください。
- 権限の問題: WMIの操作には、実行ユーザーにある程度の権限が必要です。管理者権限が必要な環境では、スクリプトを「管理者として実行」する必要があります。
- パフォーマンスの重み: WMIのクエリ(`ExecQuery`)は、FSOの操作に比べて少し「重い」処理です。ループの中で何万回も呼び出すような使い方は避けましょう。「操作の前に一度だけチェックする」のがベストプラクティスです。
- セクタエラーの検知について: 今回のコードでは「論理的な書き込み禁止」を検知していますが、物理的な「不良セクタ」そのものを完全に予知するのは、実はOSのカーネルレベルの非常に高度な領域です。しかし、`SafeFileCopy` 内でエラーを捕捉することで、「書き込みに失敗した瞬間に、被害を最小限に抑えて停止する」という、実務上極めて重要な防御ができています。
最後に
VBScriptは古い言語だと言われることもあります。しかし、その仕組みを深く理解し、今回のように「目(WMI)」と「手(FSO)」を組み合わせる知恵を持てば、現代のシステムにおいても極めて堅牢な自動化ツールになります。
「ただ動けばいい」から、「止まらない、壊さない」へ。
この一歩が、あなたを単なるスクリプターから、信頼されるエンジニアへと変えてくれます。
応援していますよ。頑張ってくださいね!
