やあ、よく来てくれたね!日々の運用業務や、ローカルPCに溜まっていくログファイルの整理に頭を悩ませていませんか?
「気がついたらディスク容量が圧迫されているけれど、手動で古いログをZIPにまとめて消すのは面倒だし、忘れてしまう……」
そんな日常の「ちょっとした面倒」を、Windowsの標準機能だけでスマートに解決してみましょう。今回は、VBScriptの強力な2つの相棒「FileSystemObject(FSO)」と「Shell.Application」を連携させて、「指定日数(例:30日)が経過したログファイルを、年月(YYYYMM)ごとのZIPファイルへ自動圧縮し、元のファイルを安全に消去する」という実戦的なアーカイブモジュールを作ります。
一見難しそうに思えるかもしれませんが、大丈夫。仕組みを一つずつ紐解いていけば、「ここをクリアすれば、VBScriptの基本はバッチリですよ」と言える確かな自信が身につきます。
それでは、優しく、かつプロの視点で深く解説していきますね。
—
1. なぜ「FSO」と「Shell.Application」の組み合わせなのか?
VBScriptでファイル操作を行う際、最も信頼性が高く、高速なのが FileSystemObject (FSO) です。しかし、FSO単体には「ファイルをZIP圧縮する」という機能がありません。
そこで登場するのが、Windowsのシェル(エクスプローラー)の機能を呼び出す Shell.Application です。
| オブジェクト名 | 得意分野(役割) |
| :— | :— |
| Scripting.FileSystemObject | ファイルの存在確認、作成日・更新日の判定、ファイルの削除や移動などの「物理制御」 |
| Shell.Application | Windows標準のZIP圧縮機能(フォルダ展開やコピー)の「UI・システム制御」 |
この2つを連携させることで、外部の圧縮ツール(Lhaplusや7-Zipなど)を一切インストールすることなく、Windows標準機能だけで完結する堅牢なポータブルスクリプトが完成します。
—
2. 【超重要】VBScriptでZIPを扱うときの「最大の罠」
コードを書く前に、プロでもよく嵌まる「最大の罠」についてお話ししておきます。
`Shell.Application` を使ってファイルをZIPにコピーする(圧縮する)とき、Windowsの内部では「非同期処理(マルチスレッド)」が行われます。
これは、「圧縮処理をバックグラウンドで裏でやっておくから、VBScriptは次の処理に進んでいいよ」という仕組みです。
何も対策をしないと、以下のような悲劇が起こります。
[悲劇のシナリオ]
1. VBScript「このファイルをZIPに圧縮してね!(CopyHere命令)」
2. Shell「了解、裏で圧縮しとくわ」
3. VBScript「よし、圧縮指示は出したから、元ファイルを削除(DeleteFile)するぞ!」
4. Shell「えっ、まだ圧縮中なのに元ファイルを消された!? 圧縮失敗!」
これを防ぐために、「ZIPファイルの圧縮が完全に終わるまで、VBScriptを一時停止(ウェイト)させて見守る」という制御が不可欠になります。この極意もコードの中でしっかりと実装していますので安心してくださいね。
—
3. 【一撃コピペOK】世代別ログアーカイブ・完全版コード
まずは、そのまま使える完成されたコードを見てみましょう。
デスクトップなどに `LogArchiver.vbs` という名前で保存して使えます。
‘ ==============================================================================
‘ 世代別ログ自動アーカイブスクリプト (LogArchiver.vbs)
‘ 概要: 指定日数以上経過したログファイルを年月(YYYYMM)別のZIPに圧縮し、元ファイルを削除する
‘ ==============================================================================
Option Explicit
‘ — [設定エリア] ————————————————————-
Const TARGET_DIR = “C:\Logs” ‘ 対象のログフォルダ(環境に合わせて変更してください)
Const SAVE_DIR = “C:\Logs\Archive”‘ ZIPを保存するフォルダ
Const RETENTION_DAYS = 30 ‘ 保存期間(これより古い更新日のファイルを圧縮)
‘ ——————————————————————————
Dim fso, shell, logFolder, file, fileDate
Dim yearMonth, zipPath, targetFolder
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set shell = CreateObject(“Shell.Application”)
‘ フォルダの存在チェック
If Not fso.FolderExists(TARGET_DIR) Then
WScript.Echo “対象フォルダが存在しません: ” & TARGET_DIR
WScript.Quit
End If
‘ 保存先フォルダがなければ自動作成
If Not fso.FolderExists(SAVE_DIR) Then
fso.CreateFolder(SAVE_DIR)
End If
‘ 対象フォルダ内のファイルをスキャン
Set logFolder = fso.GetFolder(TARGET_DIR)
For Each file In logFolder.Files
‘ 拡張子が .log のものだけを対象とする(必要に応じて変更してください)
If LCase(fso.GetExtensionName(file.Name)) = “log” Then
‘ 最終更新日からの経過日数を計算
fileDate = file.DateLastModified
If DateDiff(“d”, fileDate, Date) >= RETENTION_DAYS Then
‘ 年月(YYYYMM)を割り出してアーカイブ先のZIPパスを決定
yearMonth = Year(fileDate) & Right(“0” & Month(fileDate), 2)
zipPath = fso.BuildPath(SAVE_DIR, yearMonth & “.zip”)
‘ 1. ZIPファイルが存在しない場合は、空のZIPを新規作成
CreateEmptyZip zipPath, fso
‘ 2. ファイルをZIPに圧縮(コピー)
WScript.Echo “圧縮中: ” & file.Name & ” -> ” & yearMonth & “.zip”
CompressFileToZip file.Path, zipPath, shell, fso
‘ 3. 安全に元ファイルを削除
fso.DeleteFile file.Path, True
WScript.Echo “元ファイルを削除しました: ” & file.Name
End If
End If
Next
‘ 後片付け(オブジェクトの解放)
Set logFolder = Nothing
Set shell = Nothing
Set fso = Nothing
WScript.Echo “ログのアーカイブ処理が正常に完了しました!”
‘ ==============================================================================
‘ サブルーチン: 空のZIPファイルを作成する
‘ ==============================================================================
Sub CreateEmptyZip(path, fsoObj)
If Not fsoObj.FileExists(path) Then
Dim txtStream
‘ ZIPファイルの実体は、特定の22バイトのバイナリヘッダーを持つファイルです
Set txtStream = fsoObj.CreateTextFile(path, True)
‘ ZIPの空ヘッダー(マジックナンバー)を書き込む
txtStream.Write “PK” & Chr(5) & Chr(6) & String(18, 0)
txtStream.Close
Set txtStream = Nothing
‘ OSがファイルシステムを認識するまで一瞬待機
WScript.Sleep 500
End If
End Sub
‘ ==============================================================================
‘ サブルーチン: ファイルをZIPに安全に圧縮する(同期制御付き)
‘ ==============================================================================
Sub CompressFileToZip(filePath, zipPath, shellObj, fsoObj)
Dim zipFolder, fileCountBefore, fileCountAfter
Dim loopCount, maxWait
‘ ZIPファイルオブジェクトを取得
Set zipFolder = shellObj.NameSpace(zipPath)
‘ 圧縮前のZIP内ファイル数を記録
fileCountBefore = zipFolder.Items.Count
‘ ZIPへファイルをコピー(非同期処理の開始)
‘ コピーオプション「4 + 16 + 1024」:ダイアログ非表示、すべてはい、エラー無視
zipFolder.CopyHere filePath, 4 + 16 + 1024
‘ — [超重要] 圧縮完了を監視するループ —
‘ ファイル数が1増えるまで、またはタイムアウト(15秒)まで待機します
loopCount = 0
maxWait = 30 ‘ 0.5秒 × 30 = 15秒
Do
WScript.Sleep 500 ‘ 0.5秒待機
fileCountAfter = zipFolder.Items.Count
loopCount = loopCount + 1
‘ ファイル数が増加した=圧縮が完了したと判定
If fileCountAfter > fileCountBefore Then
Exit Do
End If
‘ タイムアウト時の安全弁
If loopCount >= maxWait Then
WScript.Echo “警告: 圧縮処理がタイムアウトしました。処理を継続します。”
Exit Do
End If
Loop
Set zipFolder = Nothing
End Sub
—
4. プログラムの心臓部を紐解く!知的なポイント解説
このコードには、ただ動くだけではない「プロの現場で耐えうる設計思想」が組み込まれています。重要なポイントを3つに絞って解説しますね。
① 空のZIPファイルを作成する「魔法の22バイト」
txtStream.Write “PK” & Chr(5) & Chr(6) & String(18, 0)
実は、WindowsにおいてZIPファイルとは「特殊なバイナリデータで始まるファイル」に過ぎません。
FSOでただの空テキストを作って拡張子を `.zip` にしても、WindowsはZIPとして認識してくれません。
上記のコードは、ZIPフォーマットの終端レコードを表す「PK」というマジックナンバーと、それに続くゼロデータ(合計22バイト)を書き込んでいます。これにより、Windowsに「これは正しい空のZIPファイルだよ」と認識させ、`Shell.Application` で操作できるようにしているのです。
② DateDiffによる「スマートな世代判定」
If DateDiff(“d”, fileDate, Date) >= RETENTION_DAYS Then
`DateDiff(“d”, …)` は、2つの日付の間の「日数(day)」の差を計算するVBScriptの標準関数です。
ファイルの最終更新日(`DateLastModified`)と「今日(`Date`)」を比較し、設定した日数(30日)以上離れているものだけを正確にフィルタリングしています。
③ 非同期の罠を突破する「監視ループ」
Do
WScript.Sleep 500
fileCountAfter = zipFolder.Items.Count
…
Loop While (ファイル数が変わらない間)
前述した「非同期の罠」を解決する極めてエレガントな方法がこれです。
ファイルをZIPに入れる前と後で、「ZIP内のアイテム数が1増えたかどうか」を0.5秒ごとにチェックしています。増えたことが確認できて初めて、安全に次のステップ(元ファイルの削除)へ進みます。
—
5. 初学者が陥りやすいエラーと回避策
実務で動かしたときに「あれ?」となりがちなポイントとその対策です。
Q1. 「書き込み権限がありません」と怒られる
- 原因: 圧縮対象のログファイルが、まだ他のシステム(IISやアプリケーションなど)によって開かれ、ロックされている可能性があります。
- 対策: スクリプトを実行するタイミングを、システムが動作していない夜間にするか、エラーが発生したファイルをスキップする処理(`On Error Resume Next`)を適切に組み込む必要があります。
Q2. 圧縮されたZIPの中身が空っぽ、または途中で消える
- 原因: 待機処理(`WScript.Sleep`)を入れていない、または待機時間が短すぎます。
- 対策: 本スクリプトに実装されている `CompressFileToZip` 内のループ処理をそのまま使用してください。これで確実に防ぐことができます。
—
6. まとめ:一歩先行く管理者へ
お疲れ様でした!
今回作成したスクリプトは、Windowsのタスクスケジューラに登録(例:毎週日曜日、深夜1時に実行)しておくことで、完全自動のログローテーションシステムとして機能します。
手動で行っていた「古いファイルの選別」「ZIPへのドラッグ&ドロップ」「元ファイルの削除」という一連の作業が、わずか1クリック、あるいは全自動で完結する快感をぜひ味わってください。
VBScriptは、一見クラシックな技術に見えますが、「何もないWindows環境でも確実に、超軽量に動作する」という、他の言語にはない絶対的な強みを持っています。
ここをクリアできれば、ファイルシステムとOSシェルを自在に操る基本はバッチリです。ぜひ、あなたの現場に合わせてカスタマイズしてみてくださいね。
何か分からないことがあれば、いつでも先輩を頼ってください。ハッピーハッキング!
