找不到日志文件更改时引发的事件

Unable to find events being raised when log file changed

提问人:Mason Kerr 提问时间:9/27/2023 更新时间:9/29/2023 访问量:35

问:

我尝试用于监视文件并检查更改,当发生更改时,它应该运行 aa 命令,这在我将文件保存在记事本中时有效,但不是从制作日志文件的实际应用程序中。 我过去看到过帖子说,这可能是由于应用程序创建了添加了新数据的日志副本,然后删除了原始数据并重命名了副本,所以我尝试查找删除、创建和重命名事件,但仍然一无所获。FileSystemWatcher

这是我一直在使用的类,它确实必须是 的派生类,因为要包含的其他功能超出了这个问题的范围。FileSystemWatcher

class LogWatcher : System.IO.FileSystemWatcher {
    [System.Management.Automation.Job[]] $Event
    [string] $LogName = 'Endpointlog.txt'
    [string] $LogFolder = ('C:\Users\' + $env:USERNAME + '\AppData\Roaming\<pathtologfolder>')
    LogWatcher () : base($this.LogFolder, $this.LogName) {
        $this.Event = (new-object System.Management.Automation.Job[] 4)
        $this.EnableRaisingEvents = $true;
        $fsaction = {
            param ( 
                [System.Object] $sender,
                [System.IO.FileSystemEventArgs] $e
            )
            $sender | fl
            $e | fl
        }
        $rnaction = {
            param ( 
                [System.Object] $sender,
                [System.IO.renamedEventArgs] $e
            )
            $sender | fl
            $e | fl
        }
        $this.NotifyFilter =[System.IO.NotifyFilters]::Attributes, [System.IO.NotifyFilters]::CreationTime,     [System.IO.NotifyFilters]::DirectoryName, [System.IO.NotifyFilters]::FileName, [System.IO.NotifyFilters]::LastAccess, [System.IO.NotifyFilters]::LastWrite, [System.IO.NotifyFilters]::Security, [System.IO.NotifyFilters]::Size 
        $this.Event[0] = register-ObjectEvent -InputObject $this -EventName changed -Action $fsaction
        $this.Event[1] = register-ObjectEvent -InputObject $this -EventName created -Action $fsaction
        $this.Event[2] = register-ObjectEvent -InputObject $this -EventName deleted -Action $fsaction
        $this.Event[3] = register-ObjectEvent -InputObject $this -EventName renamed -Action $rnaction
    }
}

并将其初始化为。$lw = [LogWatcher]::new();

日志文件每隔几秒钟更新一次,所以我希望它至少显示一个正在运行,而不是,但是我仍然只能更改一个,那就是当我打开日志并直接保存它并作为笔记时,记事本要求另存为,而不仅仅是保存为正常情况,这仍然让我认为它被复制了, 已删除并复制重命名。$lw.EventJobNot StartedJob

有什么方法可以在进行这些切换时触发任何事件?

.NET PowerShell 日志记录 事件 FileSystemWatcher

评论


答:

1赞 Santiago Squarzon 9/29/2023 #1

事件的 Action 块在不同的范围内运行,其中生成的所有输出都捕获在 .每个 PSEventJob 的 Output 属性。例如,on index 将显示引发的事件捕获的所有输出、事件的索引等:.Output0Changed1Created

$lw.Event[0].Output

但是,如果您正在进行故障排除,则使用起来要容易得多,然后输出将直接发送到控制台(也可以):Out-HostWrite-Host

$fsaction = {
    $Sender | Format-List | Out-Host
    $EventArgs | Format-List | Out-Host
}

这里值得注意的是,在 PowerShell 中,并且是自动变量,无需声明它们。$Sender$EventArgs

我也对你的班级做了一些更改,可能会帮助你简化事情:

class LogWatcher : System.IO.FileSystemWatcher {
    [System.Management.Automation.Job[]] $Event
    [string] $LogName
    [string] $LogFolder

    LogWatcher([string] $folderPath, [string] $fileName) : base($folderPath, $fileName) {
        $this.LogFolder = $folderPath
        $this.LogName = $fileName
        $this.EnableRaisingEvents = $true
        # if you want to target all possibilities, this is easier ;)
        $this.NotifyFilter = [enum]::GetValues([System.IO.NotifyFilters])

        $this.Event = 'Changed', 'Created', 'Deleted', 'Renamed' | ForEach-Object {
            Register-ObjectEvent -InputObject $this -EventName $_ -Action {
                $Sender | Format-List | Out-Host
                $EventArgs | Format-List | Out-Host

                # this is so that your watcher can keep track of the new file
                # instead of watching a file that no longer exists
                if ($EventArgs.ChangeType -eq 'Renamed') {
                    $sender.LogName = $sender.Filter = $EventArgs.Name
                }
            }
        }
    }
}

现在进行测试时,这应该在 Windows PowerShell 5.1 和 PowerShell 7+ 中都能正常工作。您应该看到所有事件都已引发。

$watcher = [LogWatcher]::new($pwd.Path, 'testingwatcher.txt')

'Creating File...'
Start-Sleep 1
$file = New-Item 'testingwatcher.txt' -Force

'Changing File...'
Start-Sleep 1
$file.LastWriteTime = [datetime]::Today

'Renaming File...'
Start-Sleep 1
$file = $file | Rename-Item -NewName 'ihaveanewname.txt' -PassThru

'Deleting File...'
Start-Sleep 1
$file.Delete()

# Cleanup - probably your class should implement IDisposable ;)
$watcher.Event.Name | Unregister-Event -SourceIdentifier { $_ }