PowerShellによる複数ファイルの監視スクリプトの解説

このプログラムは、PowerShellを使用してCSVファイルに記載された複数のファイルを監視し、それらのファイルに変更があった場合に通知するためのスクリプトです。以下は、プログラムの各部分の詳細な解説です。

CSVファイルからのファイルパスの読み込み

$csvFilePath = "C:\test.csv"
$filePaths = Import-Csv $csvFilePath -Encoding oem

プログラムはまず、指定されたCSVファイル(この例では "C:\test.csv")からファイルパスを読み込みます。Import-Csv コマンドレットを使用してCSVファイルを読み込み、各行のデータを $filePaths 変数に格納します。-Encoding oem は、CSVファイルの文字エンコーディングを指定しています。

グローバル変数の設定

$global:lastEventTime = [DateTime]::MinValue

グローバル変数 $lastEventTime は、イベントの「デバウンス」(一定時間内に発生した重複イベントの抑制)のために使用されます。最初は最小の日付値に設定されています。

FileSystemWatcherオブジェクトとイベントハンドラの設定

# 各ファイルに対してFileSystemWatcherを設定
$filePaths | ForEach-Object -Begin {$index = 0} -Process {
    
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = $_.Directory
    $watcher.Filter = $_.file
    $watcher.NotifyFilter = [System.IO.NotifyFilters]::LastWrite
    $watcher.IncludeSubdirectories = $false
    $watcher.EnableRaisingEvents = $true

    # 変更が検出された際のアクション
    $action = {
        param($source, $event)
        # イベントのデバウンス(一定時間内のイベントは無視)
        $timeSinceLastEvent = [DateTime]::Now - $global:lastEventTime

        if ($timeSinceLastEvent.TotalSeconds -lt 5) {
            return
        }
        $global:lastEventTime = [DateTime]::Now

        # イベント情報を取得
        $changeType = $event.ChangeType
        $fileName = $event.FullPath
        $timeStamp = $event.TimeGenerated
        Write-Host "ファイルが更新されました: $fileName at $timeStamp ($changeType)"
    }

    # イベントハンドラを登録
    $identifier = "FileChanged_" + $index
    Register-ObjectEvent -InputObject $watcher -EventName "Changed" -Action $action -SourceIdentifier $identifier
    $lstRegisterJob.add($identifier)
    # インデックスをインクリメント
    $index++
}

ファイルの変更が検出されたときに実行されるアクションを定義します。このアクション内で、最後のイベント発生時刻からの経過時間を計算し、5秒未満であればイベントを無視します(デバウンス)。イベントが有効であれば、変更されたファイルの名前とタイムスタンプを表示します。

Register-ObjectEvent を使用して、FileSystemWatcher オブジェクトにイベントハンドラを登録します。イベント名は "Changed" で、上で定義したアクションがイベント発生時に実行されます。$identifier は、各監視対象にユニークな識別子を割り当てるために使用されます。

イベントの登録解除

$lstRegisterJob | ForEach-Object {
    Unregister-Event -SourceIdentifier $_ -ErrorAction SilentlyContinue
}

最後のセクションは、各イベントハンドラの登録を解除するためのコードですが、コメントアウトされています。必要に応じてこのコードを使って、イベントハンドラをクリーンアップできます。

まとめ

このプログラムは、複数のファイルの変更を効率的に監視し、ファイルが更新された際に迅速に通知するための強力なツールです。特に、データの変更をリアルタイムで追跡する必要があるシステムやアプリケーションにおいて有用です。


# CSVファイルのパス
$csvFilePath = "C:\test.csv"

# CSVからファイルパスを読み込む
$filePaths = Import-Csv $csvFilePath -Encoding oem
# 最後のイベントタイムスタンプ
$global:lastEventTime = [DateTime]::MinValue

$lstRegisterJob = New-Object System.Collections.ArrayList

# 各ファイルに対してFileSystemWatcherを設定
$filePaths | ForEach-Object -Begin {$index = 0} -Process {
    
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = $_.Directory
    $watcher.Filter = $_.file
    $watcher.NotifyFilter = [System.IO.NotifyFilters]::LastWrite
    $watcher.IncludeSubdirectories = $false
    $watcher.EnableRaisingEvents = $true

    # 変更が検出された際のアクション
    $action = {
        param($source, $event)
        # イベントのデバウンス(一定時間内のイベントは無視)
        $timeSinceLastEvent = [DateTime]::Now - $global:lastEventTime

        if ($timeSinceLastEvent.TotalSeconds -lt 5) {
            return
        }
        $global:lastEventTime = [DateTime]::Now

        # イベント情報を取得
        $changeType = $event.ChangeType
        $fileName = $event.FullPath
        $timeStamp = $event.TimeGenerated
        Write-Host "ファイルが更新されました: $fileName at $timeStamp ($changeType)"
    }

    # イベントハンドラを登録
    $identifier = "FileChanged_" + $index
    Register-ObjectEvent -InputObject $watcher -EventName "Changed" -Action $action -SourceIdentifier $identifier
    $lstRegisterJob.add($identifier)
    # インデックスをインクリメント
    $index++
}


$lstRegisterJob | ForEach-Object {
    Unregister-Event -SourceIdentifier $_ -ErrorAction SilentlyContinue
}

スポンサーリンク

-IT関連
-