无法收集停止Powershell脚本

时间:2017-06-06 23:56:12

标签: powershell filesystemwatcher

我正在编写一个脚本来查看任何新mp4文件的目录,然后使用HandBrake的CLI工具转换该文件。监视目录以进行更改的逻辑单独工作,但是如果我将一个大视频放入"观看"目录转换失败,因为它在文件有时间完成复制之前,一看到新文件就会启动。

我使用do until循环检查文件是否已锁定/下载,然后在文件解锁/可写时继续。该循环作为一个独立的脚本运行,但在文件系统观察器内部使用时,它将暂停,并且该行没有任何错误:

[System.IO.FileStream] $fs = $convertingFile.OpenWrite();

无论$ ErrorActionPreference =" SilentlyContinue"被注释掉了。我已经无法收集任何日志输出,以查看脚本停止使用Start-Transcript或Out-File的原因。

我应该如何最好地收集有关脚本一旦到达此行就停止的错误信息?

Bonus:为什么这个脚本不能提供错误信息?

    $ErrorActionPreference = "SilentlyContinue"

    function Start-FileSystemWatcher {

      [CmdletBinding()]
      param(
        [Parameter()]
        [string]$Path,
        [Parameter()]
        [ValidateSet('Changed','Created','Deleted','Renamed')]
        [string[]]$EventName,
        [Parameter()]
        [string]$Filter,
        [Parameter()]
        [System.IO.NotifyFilters]$NotifyFilter,
        [Parameter()]
        [switch]$Recurse,
        [Parameter()]
        [scriptblock]$Action
      )

      #region Build  FileSystemWatcher

      $FileSystemWatcher = New-Object System.IO.FileSystemWatcher
      if (-not $PSBoundParameters.ContainsKey('Path')) {
        $Path = $PWD
      }
      $FileSystemWatcher.Path = $Path
      if ($PSBoundParameters.ContainsKey('Filter')) {
        $FileSystemWatcher.Filter = $Filter
      }

      if ($PSBoundParameters.ContainsKey('NotifyFilter')) {
        $FileSystemWatcher.NotifyFilter = $NotifyFilter
      }

      if ($PSBoundParameters.ContainsKey('Recurse')) {
        $FileSystemWatcher.IncludeSubdirectories = $True
      }

      if (-not $PSBoundParameters.ContainsKey('EventName')) {
        $EventName = 'Changed','Created','Deleted','Renamed'
      }

      if (-not $PSBoundParameters.ContainsKey('Action')) {
        $Action = {
          switch ($Event.SourceEventArgs.ChangeType) {
            'Renamed' {
              $Object = "{0} was  {1} to {2} at {3}" -f $Event.SourceArgs[-1].OldFullPath,
              $Event.SourceEventArgs.ChangeType,
              $Event.SourceArgs[-1].FullPath,
              $Event.TimeGenerated
            }

            Default {
              $Object = "{0} was  {1} at {2}" -f $Event.SourceEventArgs.FullPath,
              $Event.SourceEventArgs.ChangeType,
              $Event.TimeGenerated
            }
          }

          $WriteHostParams = @{
            ForegroundColor = 'Green'
            BackgroundColor = 'Black'
            Object = $Object
          }

          Write-Host @WriteHostParams
        }

      }

      $ObjectEventParams = @{
        InputObject = $FileSystemWatcher
        Action = $Action

      }

      foreach ($Item in $EventName) {
        $ObjectEventParams.EventName = $Item
        $ObjectEventParams.SourceIdentifier = "File.$($Item)"
        Write-Verbose "Starting watcher for Event: $($Item)"
        $Null = Register-ObjectEvent @ObjectEventParams
      }

    }

    $FileSystemWatcherParams = @{
      Path = 'X:\share\scripts\ps\converter\input'
      Recurse = $True
      NotifyFilter = 'FileName'
      Verbose = $True
      Action = {
        $Item = Get-Item $Event.SourceEventArgs.FullPath
        $WriteHostParams = @{
          ForegroundColor = 'Green'
          BackgroundColor = 'Black'
        }

        $inputFile = "${PWD}\input\$($Item.Name)".trim()
        $outputFile = "${PWD}\output\$($Item.Name)".trim()
        $logFile = "${PWD}\log\$($Item.Name).txt"
        $testLogFile = "${PWD}\log\$($Item.Name)(t).txt"

        function mp4-Func {
          Start-Transcript -path $logFile
          Write-Host "New mp4 file detected..."
          $convertingFile = New-Object -TypeName System.IO.FileInfo -ArgumentList $inputFile
          $locked = 1
          do {
            [System.IO.FileStream] $fs = $convertingFile.OpenWrite();
            if (!$?) {
                Write-Host "Can't convert yet, file appears to be loading..."
                sleep 2
            }
            else {
                $fs.Dispose()
                $locked = 0
            }
          } until ($locked -eq 0)

          Write-Host "File unlocked and ready for conversion."
          HandBrake
          Stop-Transcript
          $WriteHostParams.Object = "Finished converting: $($Item.Name)"
        }

        function HandBrake {
          .\HandBrakeCLI.exe --input "$inputFile" `
                             --output "$outputFile" `
                             --format av_mp4 `
                             --encoder x264 `
                             --vb 1700 `
                             --two-pass `
                             --aencoder copy:aac `
                             --ab 320 `
                             --arate 48 `
                             --mixdown stereo
        }

        switch -regex ($Item.Extension) {
          '\.mp4' { mp4-Func }
        }

        Write-Host @WriteHostParams
      }

    }
    @( 'Created') | ForEach-Object {
      $FileSystemWatcherParams.EventName = $_
      Start-FileSystemWatcher @FileSystemWatcherParams
    }

2 个答案:

答案 0 :(得分:0)

我认为,当您在非cmdlet代码中遇到问题时,您会发现$ErrorActionPreference仅影响cmdlet级别的错误。为此,您可能需要try / catch构造。

答案 1 :(得分:0)

基于Burt_Harris的回答(请在这个问题上回答他的答案),我改变了“do while”循环,以便它使用try / catch而不是if / else语句。通过使用$ .Exception.Message和$ .Exception.ItemName,我能够更好地理解脚本在该特定行停止的原因。

工作代码:

Do {
    Try {
      [System.IO.FileStream] $fs = $convertingFile.OpenWrite()
      $fs.Dispose()
      $locked = 0
    }
    Catch {
      $ErrorMessage = $_.Exception.Message
      $FailedItem = $_.Exception.ItemName
      Write-Host $ErrorMessage
      Write-Host $FailedItem
      Write-Host "Can't convert yet, file appears to be loading..."
      sleep 5
      continue
    }
  } until ($locked -eq 0)