如何在文件发生变化时查看文件,获取新的附加行并使用 powershell 对其执行一些操作

How to watch a file, whenever it changes, take the new additional line and perform some actions on it with powershell

如何查看日志文件,每次向其中添加一行时,我想重新格式化该行并使用 Invoke-RestMethod(基本上使用 discord 作为日志文件)将其广播到 webhook,然后也可能向控制台输出 some/same 信息。

这个问题和其他人问的类似。我一直在尝试这样做 2 周。在接下来的 post 中,他们回答了大部分问题:

Watch file for changes and run command with powershell

但是,它没有显示如何将添加的行添加到文件并对其执行操作,同时它仍在等待日志文件再次更新为下一个条目。日志文件可以连续快速更新,因此如果在程序对检测到的更改执行所述操作时日志文件发生另一个更改,则不确定这些方法是否能跟上更改。

到目前为止,我一直在循环尝试这样的事情(这不是完整的代码):

get-content '<file-name>' -tail 1 -wait

但看起来这可能会连续漏掉几行,因为在处理其他操作时,可能会出现更多行。所以看起来我可能需要以更复杂的方式执行此操作(这没关系) .只是想弄清楚该往哪个方向走。

非常感谢任何建议或方向。即使是 link 如果需要的话。

您所做的只是允许在屏幕上实时显示一个文件。你不能弄乱这样做的输出。

您使用的命令不适用于交互式用例。

您可以通过使用 SystemFileWatcher 监视文件更新,而无需执行您正在做的事情,它允许监视文件操作,然后您可以对其执行操作。


'PowerShell filesystemwatcher monitor file'

https://duckduckgo.com/?q=%27PowerShell+filesystemwatcher+monitor+file%27&t=h_&ia=web


例如来自上面的点击之一 link。

https://powershell.one/tricks/filesystem/filesystemwatcher

Monitoring Folders for File Changes

With a FileSystemWatcher, you can monitor folders for file changes and respond immediately when changes are detected. This way, you can create “drop” folders and respond to log file changes.

具体来说,根据您的用例:

Advanced Mode (asynchonous)

If you expect changes to happen in rapid succession or even simultaneously, you can use the FileSystemWatcher in asynchronous mode: the FileSystemWatcher now works in the background and no longer blocks PowerShell. Instead, whenever a change occurs, an event is raised. So with this approach, you get a queue and won’t miss any change.

On the back side, this approach has two challenges:

  • 处理事件:由于 PowerShell 本质上是单线程的,因此 响应事件并不简单,调试起来更麻烦 事件处理程序代码。

    保留 PowerShell 运行:具有讽刺意味的是,因为 FileSystemWatcher 现在不再阻止 PowerShell,这会导致另一个问题。你 需要让 PowerShell 等待事件,但您不能使用 Start-Sleep 或无限循环,因为只要 PowerShell 很忙

    • 即使它处于睡眠状态也被认为是忙碌的 - 无法处理任何事件。

Implementation

The script below does the exact same thing as the synchronous version from above, only it is event-based and won’t miss any events anymore:

# find the path to the desktop folder:
$desktop = [Environment]::GetFolderPath('Desktop')

# specify the path to the folder you want to monitor:
$Path = $desktop

# specify which files you want to monitor
$FileFilter = '*'  

# specify whether you want to monitor subfolders as well:
$IncludeSubfolders = $true

# specify the file or folder properties you want to monitor:
$AttributeFilter = [IO.NotifyFilters]::FileName, [IO.NotifyFilters]::LastWrite 

try
{
  $watcher = New-Object -TypeName System.IO.FileSystemWatcher -Property @{
    Path = $Path
    Filter = $FileFilter
    IncludeSubdirectories = $IncludeSubfolders
    NotifyFilter = $AttributeFilter
  }

  # define the code that should execute when a change occurs:
  $action = {
    # the code is receiving this to work with:
    
    # change type information:
    $details = $event.SourceEventArgs
    $Name = $details.Name
    $FullPath = $details.FullPath
    $OldFullPath = $details.OldFullPath
    $OldName = $details.OldName
    
    # type of change:
    $ChangeType = $details.ChangeType
    
    # when the change occured:
    $Timestamp = $event.TimeGenerated
    
    # save information to a global variable for testing purposes
    # so you can examine it later
    # MAKE SURE YOU REMOVE THIS IN PRODUCTION!
    $global:all = $details
    
    # now you can define some action to take based on the
    # details about the change event:
    
    # let's compose a message:
    $text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp
    Write-Host ""
    Write-Host $text -ForegroundColor DarkYellow
    
    # you can also execute code based on change type here:
    switch ($ChangeType)
    {
      'Changed'  { "CHANGE" }
      'Created'  { "CREATED"}
      'Deleted'  { "DELETED"
        # to illustrate that ALL changes are picked up even if
        # handling an event takes a lot of time, we artifically
        # extend the time the handler needs whenever a file is deleted
        Write-Host "Deletion Handler Start" -ForegroundColor Gray
        Start-Sleep -Seconds 4    
        Write-Host "Deletion Handler End" -ForegroundColor Gray
      }
      'Renamed'  { 
        # this executes only when a file was renamed
        $text = "File {0} was renamed to {1}" -f $OldName, $Name
        Write-Host $text -ForegroundColor Yellow
      }
        
      # any unhandled change types surface here:
      default   { Write-Host $_ -ForegroundColor Red -BackgroundColor White }
    }
  }

  # subscribe your event handler to all event types that are
  # important to you. Do this as a scriptblock so all returned
  # event handlers can be easily stored in $handlers:
  $handlers = . {
    Register-ObjectEvent -InputObject $watcher -EventName Changed  -Action $action 
    Register-ObjectEvent -InputObject $watcher -EventName Created  -Action $action 
    Register-ObjectEvent -InputObject $watcher -EventName Deleted  -Action $action 
    Register-ObjectEvent -InputObject $watcher -EventName Renamed  -Action $action 
  }

  # monitoring starts now:
  $watcher.EnableRaisingEvents = $true

  Write-Host "Watching for changes to $Path"

  # since the FileSystemWatcher is no longer blocking PowerShell
  # we need a way to pause PowerShell while being responsive to
  # incoming events. Use an endless loop to keep PowerShell busy:
  do
  {
    # Wait-Event waits for a second and stays responsive to events
    # Start-Sleep in contrast would NOT work and ignore incoming events
    Wait-Event -Timeout 1

    # write a dot to indicate we are still monitoring:
    Write-Host "." -NoNewline
        
  } while ($true)
}
finally
{
  # this gets executed when user presses CTRL+C:
  
  # stop monitoring
  $watcher.EnableRaisingEvents = $false
  
  # remove the event handlers
  $handlers | ForEach-Object {
    Unregister-Event -SourceIdentifier $_.Name
  }
  
  # event handlers are technically implemented as a special kind
  # of background job, so remove the jobs now:
  $handlers | Remove-Job
  
  # properly dispose the FileSystemWatcher:
  $watcher.Dispose()
  
  Write-Warning "Event Handler disabled, monitoring ends."
}

因此,根据以上内容,您可以调整它以查找 updates/modifications,然后使用

$CaptureLine = Get-Content -Path 'UNCToTheLogFile' | Select-Object -Last 1

或者

$CaptureLine = Get-Content -Path  'D:\temp\book1.csv' -Tail 1

然后做你想做的事。