我尝试使用
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.Event
至少显示一个正在运行的Job
而不是Not Started
,但是我仍然只能更改一个Job
,那就是当我打开日志并直接保存并作为注释,记事本要求另存为而不是正常保存,这仍然让我认为它被复制,删除和复制重命名。
有什么方法可以让我在进行这些切换时触发任何事件吗?
.Output
的PSEventJob
属性中捕获。例如,索引 .Output
上的 0
将显示由 Changed
引发的事件捕获的所有输出,索引 1
的 Created
事件等:
$lw.Event[0].Output
但是,如果您要进行故障排除,则使用
Out-Host
会更容易,然后输出会直接发送到控制台(Write-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 { $_ }