Powershell FileSystemWatcher - 避免在创建时重复操作
Posted
技术标签:
【中文标题】Powershell FileSystemWatcher - 避免在创建时重复操作【英文标题】:Powershell FileSystemWatcher - Avoiding duplicate action on Create 【发布时间】: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 文件放入监视文件夹时出现一次
【问题讨论】:
【参考方案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 个唯一文件,它将跳过它们。
【讨论】:
以上是关于Powershell FileSystemWatcher - 避免在创建时重复操作的主要内容,如果未能解决你的问题,请参考以下文章
powershell PowerShell:启动PowerShell作为其他用户提升
powershell [提示输入powershell] #powershell #input #prompt