Как использовать PowerShell, чтобы сказать, когда серия файлов была добавлена ​​в сеть - PullRequest
1 голос
/ 28 января 2020

Итак, у меня есть скрипт powershell, в основном взятый из подобного вопроса, который может обнаружить, когда определенный тип файла добавляется в определенную сеть, и отправлять электронные письма, когда это происходит:

Function Watcher{

param ($folder, $filter, $to, $Subject)



$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{
    IncludeSubdirectories = $true
    EnableRaisingEvents = $true
}

$changeAction = [scriptblock]::Create('

        $path = $Event.SourceEventArgs.FullPath
        $name = $Event.SourceEventArgs.Name
        $changeType = $Event.SourceEventArgs.ChangeType
        $timeStamp = $Event.TimeGenerated
        Write-Host "The file $name was $changeType at $timeStamp"

        $Body = "The file $name was $changeType at $timeStamp"

        Email $to $Subject $Body

 ')

    Register-ObjectEvent $Watcher -EventName "Created" -Action $changeAction


}

Однако Я хочу изменить это так, чтобы это могло быть полезно для этого приложения: сейчас есть инструмент, добавляющий данные (файлы .datx) в сеть (несколько файлов в минуту), и я хотел бы получать уведомление по электронной почте в тот момент, когда данные готовятся к записи. Как мне проще всего изменить это так, чтобы при запуске первоначального наблюдателя он ждал, чтобы это произошло снова, и сбрасывает, если так, но затем продолжает, если нет? Или лучше создать совершенно новый сценарий? По сути, как сделать так, чтобы наблюдатель активировался одиночным файлом .datx, загружаемым в сеть, но не вызывал его потоком (кроме самого последнего)

1 Ответ

1 голос
/ 28 января 2020

Вы можете использовать следующий пакетный подход :

  • Определить длину скользящего временного окна, которое сбрасывается, если в нем создается новый файл; продолжайте собирать события, пока они поступают в это скользящее окно.

    • Чтобы предотвратить бесконечный рост коллекции, определите максимальный размер пакета, при котором пакет обрабатывается, даже если ожидают дальнейшие события.
  • После истечения временного окна без поступления новых событий обработайте имеющийся пакет, т. Е. События, собранные на данный момент, затем запустите новый пакет.

  • Предостережение :

    • Класс System.IO.FileSystemWatcher может сообщить повторяющихся событий.

    • Приведенный ниже код устраняет дубликаты в данном пакете , но не в пакетах , что потребует немного больше усилий - см. Исходный код комментарии.

  • Замечания по реализации:

    • Вместо использования блока сценария -Action, переданного в Register-ObjectEvent для обработки событий они обрабатываются синхронно - с таймаутом - в Wait-Event l oop.

    • Wait-Event использует событие PowerShell queue и поэтому обычно не пропускает события (хотя это может произойти на уровне. NET в ситуациях большого объема); в отличие от этого FileSystemWatcher аналогичный метод WaitForChanged делает , а не события очереди и сообщает только одно событие, если происходит, пока метод ожидает.

try {

  # Specify the target folder: the system's temp folder in this example.
  $dir = (Get-Item -EA Ignore temp:).FullName; if (-not $dir) { $dir = $env:TEMP }

  # Create and initialize the watcher.
  # Note the [ordered] to ensure that .EnableRaisingEvents is set last.
  $watcher = [System.IO.FileSystemWatcher] [ordered] @{
    Filter              = '*.datx'
    Path                = $dir
    EnableRaisingEvents = $true
  }

  # To simulate file creation, create *.datx files in the folder printed
  # mentioned in the following status message.
  Write-Host "Watching $dir for creation of $($watcher.Filter) files..."

  # Register for (subscribe to) creation events:
  # Determine a unique event-source ID...
  [string] $sourceId = New-Guid
  # ... and register for the watcher's Created event with it.
  Register-ObjectEvent $watcher -EventName Created -SourceIdentifier $sourceId

  # Initialize the ordered hashtable that collects all file names for a single 
  # batch.
  # Note: Since any given file creation can trigger *multiple* events, we 
  #       use an ordered hashtable (dictionary) to ensure that each file is 
  #       only reported once.
  #       However, *across batches* duplicates can still occur - see below.
  $batch = [ordered] @{}

  # Determine the sliding time window during which newly created files are 
  # considered part of a single batch.
  # That is, once a file has been created, each additional file created
  # within that time window relative to previous file becomes part of the
  # same batch.
  # When a time window elapses without a new file having been created, the
  # batch is considered complete and processed - see max. batch-size exception
  # below.
  # IMPORTANT:
  #  * The granularity is *seconds*, so the time window must be at least 1 sec.
  #  * Seemingly independently of the length of this window, duplicate events
  #    are likely to occur across batches the less time has elapsed between
  #    the end of a batch and the start of a new one - see below.
  $batchTimeWindowSecs = 5

  # How many names to allow a batch to contain at most, even if more
  # files keep getting created in the sliding time window.
  $maxBatchSize = 100

  while ($true) {
    # Run indefinitely; use Ctrl-C to exit.

    # Wait for events in a sliding time window of $batchTimeWindowSecs length.
    # Note: Using Wait-Event in a loop (1 event per iteration) is *more* 
    #       predictable than the multi-event collecting Get-Event in terms of
    #       avoiding duplicates, but duplicates do still occur.
    $batch.Clear()
    while ($evt = Wait-Event -SourceIdentifier $sourceId -Timeout $batchTimeWindowSecs) {
      $evt | Remove-Event  # By default, events linger in the queue; they must be removed manually.
      # Add the new file's name to the batch (unless already present)
      # IMPORTANT:
      #  * Duplicates can occur both in a single batch and across batches.
      #  * To truly weed out all duplicates, you'd have to create a session-level
      #    dictionary of the files' names and their creation timestamps.
      #    With high-volume file creation, this session-level dictionary could
      #    grow large; periodic removal of obsolete entries would help.
      $batch[$evt.SourceArgs.Name] = $null # dummy value; it is the *keys* that matter.
      Write-Host ✔ -NoNewline # status output: signal that a new file was created
      # If the max. batch size has been reached, submit the batch now, even if further
      # events are pending within the timeout window.
      if ($batch.Count -ge $maxBatchSize) { 
        Write-Warning "Max. batch size of $maxBatchSize reached; force-submitting batch."
        break
      }
    }

    # Completed batch available?
    if ($batch.Count) {      
      # Simulate processing the batch.
      Write-Host "`nBatch complete: Sending email for the following $($batch.Count) files:`n$($batch.Keys -join "`n")"                                            #`
      # Start a new batch.
      $batch.Clear()
    }
    else {
      Write-Host . -NoNewline # status output: signal that no new files were created in the most recent time window.
    }

  }

}
finally {
  # Clean up:
  # Unregister the event subscription.
  Unregister-Event -SourceIdentifier $sourceId
  # Dispose of the watcher.
  $watcher.Dispose() 
}

Пример вывода при создании сначала пакета из 3 файлов, а затем другого с 5:

Watching C:\Users\jdoe\AppData\Local\Temp for creation of *.datx files...
............✔✔✔
Batch complete: Sending email for the following 3 files:
1.datx
2.datx
3.datx
.✔✔✔✔✔
Batch complete: Sending email for the following 5 files:
4.datx
5.datx
6.datx
7.datx
8.datx
....................
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...