PowerShell - 监控文件夹内容

4
我希望能够在短时间内监测文件夹中的变化,当有大量文件被创建或其他变化发生时。以下代码可以工作,但并不能捕捉到所有的变化。
$folder = ’C:\Data’
$timeout = 1000
$FileSystemWatcher = New-Object System.IO.FileSystemWatcher $folder
Write-Host ”Press CTRL+C to abort monitoring $folderwhile ($true) {
$result = $FileSystemWatcher.WaitForChanged(‘all’, $timeout)
if ($result.TimedOut -eq $false)
{
Write-Warning (‘File {0} : {1}’ -f $result.ChangeType, $result.name)
}
}
Write-Host ’Monitoring aborted.’

如果我在 C:\Data 上使用它,它可以工作,但是

我创建一个 .txt 文件,它会两次输出 new text document.txt。然后我为新的 txt 填写名称,它会输出三次。或者反过来。

请查看下面的输出:

  • 在我的文件夹中创建一个 hello.txt
  • 创建一个名为 HiThere 的新文件夹
  • hello.txt 重命名为 someTxt.txt
  • 然后删除它们两个

输出:

`Press CTRL+C to abort monitoring C:\Data
WARNING: File Created : New Text Document.txt
WARNING: File Changed : New Text Document.txt
WARNING: File Changed : New Text Document.txt
WARNING: File Changed : hello.txt
WARNING: File Created : New folder
WARNING: File Renamed : HiThere
WARNING: File Renamed : someTxt.txt
WARNING: File Changed : someTxt.txt
WARNING: File Changed : someTxt.txt
WARNING: File Changed : someTxt.txt
WARNING: File Deleted : someTxt.txt
WARNING: File Deleted : HiThere`

更多问题:如果我在网络驱动器上使用它,那么并不是所有更改都被捕获。 (而这正是此脚本的重点,监视映射驱动器中的文件夹)。
通过仅更改文件夹路径,在您的计算机上测试代码。
使用Powershell ISE 3.0。

请注意,FileSystemWatcher在监视文件系统方面的可靠性不佳,通常建议使用其他方法来监视文件系统。 - Gerald Schneider
@GeraldSchneider 你好,谢谢你的回复。我明白了,之前不知道这个情况,但是也许有人有想法可以改进一下代码。我主要是在玩 PowerShell 并尝试寻找新的酷炫用法。偶然发现了这个小项目,想试一试。如果没有解决方案,我会放弃,但现在还不会 :) - CM2K
2个回答

2

除了while($true)循环,您尝试过使用“Register-ObjectEvent”吗?

我刚刚使用这种方法测试了我的一个脚本,并且可以轻松地获取2000个空文件(在PowerShell中生成)。不幸的是,这是在本地计算机上进行的。

说明:像平常一样定义函数即可。您使用的命令是:

Start-BackupScript -WatchFolder "C:\temp\my watch folder\" -DestinationFolder "C:\temp\backup\"

脚本现在监视"C:\temp\my watch folder\"中创建的新文件,并将它们移动到"C:\temp\backup\"。同时,它还会在文件名后追加日期和时间。
假设您使用以上参数启动了脚本。您现在将"hello_world.txt"放入监视文件夹。脚本将把文件移动到"C:\temp\backup\",并且新文件名是:"hello_world_2016-02-10_10-00-00.txt"
脚本在后台运行。如果您想知道它的运行情况,请使用以下命令:
Get-Job $backupscript -Keep

在那里,你可以看到它做了什么以及何时做的。请注意,"-Keep"参数会将输出保留在“日志”中,以便稍后检查。

脚本:

function Start-BackupScript
{
  [CmdletBinding()]
  Param
  (
    [Parameter()]
    [String]$WatchFolder,
    [Parameter()]
    [String]$DestinationFolder
    )
  Process 
  {
    $filter = '*.*'                           
    $fsw = New-Object IO.FileSystemWatcher $WatchFolder, $filter -Property @{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName,     LastWrite'} 
    $action = {
      $fileMissing = $false 
      $FileInUseMessage = $false 
      $copied = $false 
      $file = Get-Item $Args.FullPath 
      $dateString = Get-Date -format "_yyyy-MM-dd_HH-mm-ss" 
      $DestinationFolder = $event.MessageData 
      $DestinationFileName = $file.basename + $dateString + $file.extension 
      $resultfilename = Join-Path $DestinationFolder $DestinationFileName 
      Write-Output ""
      while(!$copied) { 
        try { 
          Move-Item -Path $file.FullName -Destination $resultfilename -ErrorAction Stop
          $copied = $true 
        }  
        catch [System.IO.IOException] { 
          if(!$FileInUseMessage) { 
            Write-Output "$(Get-Date -Format "yyyy-MM-dd @ HH:mm:ss") - $file in use. Waiting to move file"
            $FileInUseMessage = $true 
          } 
          Start-Sleep -s 1 
        }  
        catch [System.Management.Automation.ItemNotFoundException] { 
          $fileMissing = $true 
          $copied = $true 
        } 
      } 
      if($fileMissing) { 
        Write-Output "$(Get-Date -Format "yyyy-MM-dd @ HH:mm:ss") - $file not found!"
      } else { 
        Write-Output "$(Get-Date -Format "yyyy-MM-dd @ HH:mm:ss") - Moved $file to backup! `n`tFilename: `"$resultfilename`""
      }
    }
    $backupscript = Register-ObjectEvent -InputObject $fsw -EventName "Created" -Action $action -MessageData $DestinationFolder
    Write-Host "Started. WatchFolder: `"$($WatchFolder)`" DestinationFolder: `"$($DestinationFolder)`". Job is in: `$backupscript"
  }
}

我刚刚将我的脚本添加到了帖子中。请注意,$action是一个脚本块,每次创建文件时都会执行。 - Jonas Andersen
谢谢。你能写一个简短的“如何使用”说明吗?附在这里,供我和未来的读者参考。 - CM2K
我现在正在尝试修复子目录,因为它似乎没有复制整个文件夹,只是其中的一些随机文件。 - CM2K
另外,尝试修改它以在删除时发出警报,或执行某种删除警报。 - CM2K
如果想要子目录,那么将其更改为 $true。如果您想要文件夹,则可以将 $filter 变量更改为 '*'。关于日志记录,您可以编写任何内容。只需将 Write-Output 变量更改为所需内容即可。如果您想要删除,则将其添加到 ArrayList EventName 中。在此处阅读事件名称:https://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(v=vs.110).aspx#Anchor_5 - Jonas Andersen
显示剩余3条评论

0
你看过Register-WMIEvent吗?
类似这样:
Register-WmiEvent -Query "SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'CIM_DataFile' and TargetInstance.Path = '\\Users\\Administrator\\' and targetInstance.Drive = 'C:' and (targetInstance.Extension = 'txt' or targetInstance.Extension = 'doc' or targetInstance.Extension = 'rtf') and targetInstance.LastAccessed > '$($cur)' " -sourceIdentifier "Accessor" -Action $action   `

你可以监视一个文件夹,然后监视文件夹中特定的扩展名。然后设置一个PowerShell脚本块来处理任何访问。如果您感兴趣,这里有更多信息:https://blog.varonis.com/practical-powershell-for-it-security-part-i-file-event-monitoring/

同意上面一些评论,文件监视不可靠--会出现延迟和故障。无论如何,希望这有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接