【问题标题】:Powershell FileSystemWatcher - Avoiding duplicate action on CreatePowershell FileSystemWatcher - 避免在创建时重复操作
【发布时间】:2019-10-08 08:39:20
【问题描述】:

FileSystemWatcher 在事件中触发两次是 Powershell 中的一个已知问题。我正在尝试解决此问题,因为我正在查看正在创建的文件,然后将其推送到打印机。双重触发意味着我得到了重复的打印输出

我知道以前有人问过这个问题,但是当谈到 Powershell(实际上是一般的脚本)时,我是一个完全的新手,所以一些答案已经直接浮现在我的脑海中

在代码中,我正在查看一个文件夹,然后将子目录名称作为打印机名称传递给发送作业。这是因为正在使用的软件正在将 pdf 文件从远程位置复制到这些文件夹中(由于 citrix,该软件无法直接访问打印机)

### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = "L:\Label\"
    $watcher.Filter = "*.*"
    $watcher.IncludeSubdirectories = $true
    $watcher.EnableRaisingEvents = $true 

### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
    $action = { $path = $Event.SourceEventArgs.FullPath
                $changeType = $Event.SourceEventArgs.ChangeType
                $printer = Split-Path (Split-Path $path -Parent) -Leaf
                $logline = "$(Get-Date), $changeType, $path, $printer"
                Add-content "c:\prog\log.txt" -value $logline
                C:\prog\SumatraPDF.exe -print-to "\\http://srv:631\$printer" $path
              }    

### DECIDE WHICH EVENTS SHOULD BE WATCHED 
    Register-ObjectEvent $watcher "Created" -Action $action
    while ($true) {sleep 5}

我希望看到打印命令(Sumatra 调用)仅在将 pdf 文件放入监视文件夹时出现一次

【问题讨论】:

    标签: powershell filesystemwatcher


    【解决方案1】:

    我认为 FileSystemWatcher 在事件上触发两次不是已知问题,而不是您从哪里获得该信息。

    不管怎样,如果我是你,我不会自己在 Powershell 中编写 FileSystemWather 事件,这真的很痛苦。

    相反,您可以使用 Powershell Guard,只需传递打印命令而不是 TestCommand。 https://github.com/smurawski/PowerShellGuard

    PowerGuard 所做的只是抽象 FileSystemWatcher 的使用。您可以在 Powershell 脚本中创建打印命令,然后让 PowerGuard 使用 -TestCommand "Print.ps1 .\PathToYourFile" 调用您的脚本

    最终解决方案(由发帖人本人):

    dir \\srv\label\prnlblCuts\*.pdf | New-Guard -TestCommand "C:\PROG\SumatraPDF.exe -print-to \\srv-tsv:631\prnlblCuts" -TestPath "$($_.FullName)" -Wait
    

    【讨论】:

    • 我只说“已知问题”,因为快速谷歌发现很多人抱怨事件的多次触发。我敢肯定这是设计使然,但处理起来真的很痛苦:)
    • 我现在正在玩 PowershellGuard。不过我的困惑是我是否仍然可以像在原始 Powershell 脚本中那样传递变量?
    • 我明白你在说什么,但我认为这个问题被广泛歪曲了。很多人都在使用 FileSystemWatcher 并理解它触发的事件。如果您需要使用 PowerGuard 模块的示例,请告诉我。
    • 啊!好的,我会试一试:)
    • 我看不到使用 Guard 映射的网络驱动器。如果我执行 -Path c:\ -PathFilter "*.pdf",则会触发脚本但是我需要查看 l:\(映射的网络驱动器)。不过似乎不允许我这样做
    【解决方案2】:

    这里没有告诉你应该做什么,不应该做什么,而是按照你的要求去做:

    ### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
    $global:canDoEvent = $True #NEW
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = "L:\Label\"
    $watcher.Filter = "*.*"
    $watcher.IncludeSubdirectories = $true
    $watcher.EnableRaisingEvents = $true 
    

    在检测到事件后定义操作

    $action = { if ($global:canDoEvent) { #NEW
                    $global:canDoEvent = $False #NEW
                    $path = $Event.SourceEventArgs.FullPath
                    $changeType = $Event.SourceEventArgs.ChangeType
                    $printer = Split-Path (Split-Path $path -Parent) -Leaf
                    $logline = "$(Get-Date), $changeType, $path, $printer"
                    Add-content "c:\prog\log.txt" -value $logline
                    C:\prog\SumatraPDF.exe -print-to "\\http://srv:631\$printer" $path
                }
              }    
    

    决定应该观看哪些事件

    Register-ObjectEvent $watcher "Created" -EventName newFile -Action $action #NEW
    do { #NEW
         $global:canDoEvent = $True
         Wait-Event -SourceIdentifier newFile -Timeout 1
       } while ($True)
         
    

    这可能需要调整,我不是专家,但就是这样。

    基本上,添加一个全局布尔值 var = True,将您的等待事件置于 do-while 循环内的超时状态,在每个循环中将变量设为 true,然后在您的事件操作中将其设为 false。您的超时将定义事件可以触发的频率。一秒钟应该足以防止多次触发事件。显然,如果在某些情况下可以在同一秒内创建和打印超过 1 个唯一文件,它将跳过它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多