PowerShell使用FileSystemWatcher监视文件或文件夹的更改

FileSystemWatcher可以监视文件或文件夹的更改,因此在将新文件复制到文件夹或删除或更改文件时,可以立即通知您的PowerShell代码。

通常,您会找到用于同步监视的示例代码,如下所示:

# make sure you adjust this

$PathToMonitor = "C:\scripts\test"

 

 

$FileSystemWatcher = New-Object System.IO.FileSystemWatcher

$FileSystemWatcher.Path  = $PathToMonitor

$FileSystemWatcher.IncludeSubdirectories = $true

 

Write-Host "Monitoring content of $PathToMonitor"

explorer $PathToMonitor

while ($true) {

  $Change = $FileSystemWatcher.WaitForChanged('All', 1000)

  if ($Change.TimedOut -eq $false)

  {

      # get information about the changes detected

      Write-Host "Change detected:"

      $Change | Out-Default

 

      # uncomment this to see the issue

      #Start-Sleep -Seconds 5

  }

  else

  {

      Write-Host "." -NoNewline

  }

}

 

这个例子很好用。将文件添加到要监视的文件夹或进行更改时,将检测到更改类型。您可以轻松地获取该信息并调用操作。例如,在您的IT中,人们可以将带有说明的文件拖放到放置文件夹中,并且脚本可以响应这些文件。

但是,这种方法有一个缺点:检测到更改时,控制权将返回到脚本,以便它可以处理更改。如果在您的脚本不再等待事件时发生另一个文件更改,则它将丢失。您可以轻松地自己检查一下:

在检测到更改时执行的代码中添加冗长的语句,例如“ Start-Sleep -Seconds 5”,然后将多个更改应用于您的文件夹。如您所见,将检测到第一个更改,但是在PowerShell保持繁忙的五秒钟间隔内,所有其他更改事件都丢失了。

在下一个的提示中,我们将确保您的FileSystemWatcher不会跳过任何更改!

在上一个技巧中,我们介绍了FileSystemWatcher,并说明了当您的处理程序代码花费太长时间时,它如何丢失文件系统更改。

要正确使用FileSystemWatcher,应异步使用它并确保它使用队列。因此,即使您的脚本忙于处理文件系统更改,它也应继续记录新的文件系统更改,并在PowerShell完成对先前更改的处理后再进行处理。

# make sure you adjust this to point to the folder you want to monitor

$PathToMonitor = "C:\scripts\test"

 

explorer $PathToMonitor

 

$FileSystemWatcher = New-Object System.IO.FileSystemWatcher

$FileSystemWatcher.Path  = $PathToMonitor

$FileSystemWatcher.IncludeSubdirectories = $true

 

# make sure the watcher emits events

$FileSystemWatcher.EnableRaisingEvents = $true

 

# define the code that should execute when a file change is detected

$Action = {

    $details = $event.SourceEventArgs

    $Name = $details.Name

    $FullPath = $details.FullPath

    $OldFullPath = $details.OldFullPath

    $OldName = $details.OldName

    $ChangeType = $details.ChangeType

    $Timestamp = $event.TimeGenerated

    $text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp

    Write-Host ""

    Write-Host $text -ForegroundColor Green

   

    # you can also execute code based on change type here

    switch ($ChangeType)

    {

        'Changed' { "CHANGE" }

        'Created' { "CREATED"}

        'Deleted' { "DELETED"

            # uncomment the below to mimick a time intensive handler

            <#

            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

        }

        default { Write-Host $_ -ForegroundColor Red -BackgroundColor White }

    }

}

 

# add event handlers

$handlers = . {

    Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Changed -Action $Action -SourceIdentifier FSChange

    Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action $Action -SourceIdentifier FSCreate

    Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Deleted -Action $Action -SourceIdentifier FSDelete

    Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Renamed -Action $Action -SourceIdentifier FSRename

}

 

Write-Host "Watching for changes to $PathToMonitor"

 

try

{

    do

    {

        Wait-Event -Timeout 1

        Write-Host "." -NoNewline

       

    } while ($true)

}

finally

{

    # this gets executed when user presses CTRL+C

    # remove the event handlers

    Unregister-Event -SourceIdentifier FSChange

    Unregister-Event -SourceIdentifier FSCreate

    Unregister-Event -SourceIdentifier FSDelete

    Unregister-Event -SourceIdentifier FSRename

    # remove background jobs

    $handlers | Remove-Job

    # remove filesystemwatcher

    $FileSystemWatcher.EnableRaisingEvents = $false

    $FileSystemWatcher.Dispose()

    "Event Handler disabled."

}

运行此命令时,将监视$ PathToMonitor中指定的文件夹的更改,并且当更改发生时,将发出一条消息。当您按CTRL + C时,脚本结束,并且所有事件处理程序都将在finally块中自动清除。

PS F:\> F:\FileSystemWatcherTest2.ps1
Watching for changes to C:\scripts\test
....
C:\scripts\test\新建文本文档.txt was Created at 2020/10/31 7:39:18
.....
C:\scripts\test\新建文本文档.txt was Changed at 2020/10/31 7:39:23
.....
C:\scripts\test\新建文本文档.txt was Changed at 2020/10/31 7:39:28
.
C:\scripts\test\新建文本文档.txt was Deleted at 2020/10/31 7:39:29
..............
PS F:\> 

更重要的是:此代码在内部使用队列,因此当短时间内发生许多更改时,一旦PowerShell不再繁忙,所有更改都将得到处理。您可以通过取消注释代码中删除事件的标记部分来对此进行测试。现在,无论何时删除文件,处理程序都会花费额外的4秒钟。

即使删除了大量文件,它们最终也会全部列出。如前所述,此处介绍的方法比基于WaitForChanged()的同步处理程序更加可靠。

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值