【问题标题】:Looping through files with Powershell after using System.IO.FileSystemWatcher使用 System.IO.FileSystemWatcher 后使用 Powershell 循环文件
【发布时间】:2016-09-08 23:52:18
【问题描述】:

在监视文件夹以创建扩展名为 .csv 的新文件的 PowerShell 脚本方面需要一些帮助。
当检测到新文件的创建时,会发生以下操作……

  1. 文件的详细信息发送到日志文件
  2. 文件的副本被发送到另一个名为“1_ToBeProcessed\MyImport.csv”的文件夹(注意文件已重命名为 MyImport.csv)
  3. 文件已移至目录“\MYSERVER\MYCOMPANY\MYFOLDER\MyHistory”(使用其原始文件名)
  4. 调用一个表达式来运行一个 .bat 文件,该文件将获取位于“\MYSERVER\MYCOMPANY\MYFOLDER\1_ToBeProcessed”中的文件并将该文件导入应用程序。
  5. 然后该脚本会休眠 60 秒以允许导入完成,然后再处理下一个文件。 除非在脚本运行时创建另一个文件,否则此脚本一切正常。
    同一类型的多个文件可能会同时命中监视文件夹。因此,脚本可能会遍历五个文件,然后另一个文件可能会进入目录。发生这种情况时,脚本似乎会重新开始并开始循环遍历文件……但它会一遍又一遍地循环相同的文件。 我希望有人能指出我在这个脚本中做错了什么。由于添加了新文件,我如何让它在重新开始之前完成当前循环中正在处理的文件? 我们将不胜感激任何可以提供的帮助!

这是我目前拥有的......

#Define watcher; Set path to watch; Set filter on file type
$filewatcher = New-Object System.IO.FileSystemWatcher
$filewatcher.Path = "\\MYSERVER\MYCOMPANY\MYFOLDER"
$filewatcher.Filter = "*.csv"                     

#Define "move to" and "copy to" paths
$moveTo = "\\MYSERVER\MYCOMPANY\MYFOLDER\MyHistory"
$copyTo = "\\MYSERVER\MYCOMPANY\MYFOLDER\1_ToBeProcessed\MyImport.csv"


#Define actions after an Event is Detected
$action = {$files = Get-ChildItem -Path $filewatcher.Path -Filter filewatcher.Filter 
        foreach ($file in $files)
        {
        #Define variables for log file
        $changeType = $Event.SourceEventArgs.ChangeType
        $logline = "$(Get-Date), $changeType, $file"
        #Actions to take
        Add-Content "\\MYSERVER\MYCOMPANY\MYFOLDER\3_Log\MyImportLog.txt" -value $logline
        Copy-Item $file.FullName -Destination $copyTo
        Move-Item $file.FullName -Destination $moveTo -Force
        Invoke-Expression "& '\\MYSERVER\MYCOMPANY\MYFOLDER\4_Scripts\PSscriptToRunBATfile.ps1'"
        #Pause the script for 60 seconds to allow it to finish posting the import before going to the next record
        Start-Sleep -Seconds 60
        }
        }

#Decide which events should be watched and set check frequency 
$onCreated = Register-ObjectEvent -InputObject $filewatcher -EventName "Created" -SourceIdentifier FileCreated -Action $action

【问题讨论】:

    标签: powershell filesystemwatcher


    【解决方案1】:

    我建议不要循环,而是在创建/更改文件时对其进行处理。也许如果你有很多文件要开始,你要么:

    (a) 首先循环(并且只循环一次)。然后启用文件观察器来处理之后哪些文件发生了变化。

    (b) 使用 FileChanged 和 FileCreated 启用文件观察器,然后“触摸”所有文件以触发您的代码。

    # based on the script by By BigTeddy 05 September 2011
    # simplified by Andy Myatt, to use one script block
    # https://gallery.technet.microsoft.com/scriptcenter/Powershell-FileSystemWatche-dfd7084b
    
    param(
        [string]$folderToWatch = "D:\Temp"
      , [string]$filter        = "*.*"
      , [string]$logFile       = "D:\Temp\Temp2\filewatcher.log"
    )
    
    # In the following line, you can change 'IncludeSubdirectories to $true if required.
    $fsw = New-Object IO.FileSystemWatcher $folderToWatch, $filter -Property @{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
    
    # This script block is used/called by all 3 events and:
    # appends the event to a log file, as well as reporting the event back to the console
    $scriptBlock = {
    
      # REPLACE THIS SECTION WITH YOUR PROCESSING CODE
      $logFile = $event.MessageData # message data is how we pass in an argument to the event script block
      $name = $Event.SourceEventArgs.Name
      $changeType = $Event.SourceEventArgs.ChangeType
      $timeStamp = $Event.TimeGenerated
      Write-Host "$timeStamp|$changeType|'$name'" -fore green
      Out-File -FilePath $logFile -Append -InputObject "$timeStamp|$changeType|'$name'"
      # REPLACE THIS SECTION WITH YOUR PROCESSING CODE
    
    }
    
    # Here, all three events are registered.  You need only subscribe to events that you need:
    Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -MessageData $logFile -Action $scriptBlock
    Register-ObjectEvent $fsw Deleted -SourceIdentifier FileDeleted -MessageData $logFile -Action $scriptBlock
    Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -MessageData $logFile -Action $scriptBlock
    
    # To stop the monitoring, run the following commands:
    #  Unregister-Event FileDeleted  ;  Unregister-Event FileCreated  ;  Unregister-Event FileChanged
    
    
    #This script uses the .NET FileSystemWatcher class to monitor file events in folder(s).
    #The advantage of this method over using WMI eventing is that this can monitor sub-folders.
    #The -Action parameter can contain any valid Powershell commands.
    #The script can be set to a wildcard filter, and IncludeSubdirectories can be changed to $true.
    #You need not subscribe to all three types of event.  All three are shown for example.
    

    【讨论】:

    • 谢谢!抱歉延迟回复...有胃病!当我最初研究解决方案时,我遇到了 BigTeddy 的帖子。我是 Powershell 的新手,仍在学习。最终,我选择了循环,因为这是我学习和理解的过程。我想按日期/时间顺序进行,但是,我并没有考虑如何去做。我会回去再研究一下,看看我能不能让它为我工作。谢谢!
    • 没问题,@mdgaw,如果可行,请标记为答案和/或投票
    【解决方案2】:

    我认为您可能遇到了某种文件锁定问题,但如果不知道您的 PSscriptToRunBATfile.ps1 文件中的内容,就很难判断。

    您的 filewatcher 在默认的 NotifyEventsLastWrite | FileName | DirectoryName 上触发,然后您循环该目录。但是,您的 get-childitem 命令不一定会按照它们被复制的顺序返回文件。

    更好的解决方案是让您根据您的 $Event 对象执行工作并更改您的 PS1 文件,将导致事件的文件作为输入参数:

    $action = {$file = $Event.SourceEventArgs.FullPath
      #Define variables for log file
      $changeType = $Event.SourceEventArgs.ChangeType
      $logline = "$(Get-Date), $changeType, $file"
      #Actions to take
      Add-Content "\\MYSERVER\MYCOMPANY\MYFOLDER\3_Log\MyImportLog.txt" -value $logline
      Copy-Item $file -Destination $copyTo
      Move-Item $file -Destination $moveTo -Force
      Invoke-Expression "& '\\MYSERVER\MYCOMPANY\MYFOLDER\4_Scripts\PSscriptToRunBATfile.ps1' -InputFile $file"
    }
    

    注意:您可能希望将InternalBufferSize 增加到默认的 8k 以上,以免错过任何更改:

        $filewatcher.InternalBufferSize = 32kb
    

    【讨论】:

    • 首先让我说我是 Powershell 的新手。因此,我仍在学习事件以及我可以用它们做什么。关于文件 PSscriptToRunBATfile.ps1 中的内容,该脚本的目的是获取在一个程序中创建的文件并将其自动导入另一个程序。它运行一个系统生成的宏来进行导入。由于“$action”似乎在另一个文件进入目录时重新开始,所以我使用一些 vbscript 每 5 分钟将导入文件移动到我的文件观察程序目录。在下一批进来之前已经完成了导入。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    相关资源
    最近更新 更多