【问题标题】:Unable to gather error info from halting Powershell script无法从停止的 Powershell 脚本中收集错误信息
【发布时间】:2017-06-07 14:03:16
【问题描述】:

我正在编写一个脚本,它将监视一个目录中是否有任何新的 mp4 文件,然后使用 HandBrake 的 CLI 工具转换文件。监视目录以进行更改的逻辑本身可以工作,但是如果我将一个大视频放到“已监视”目录中,则转换会失败,因为它会在文件有时间完成复制之前立即启动,因为它看到一个新文件。

我正在使用一个直到循环来检查文件是否被锁定/下载,然后在文件解锁/可写后继续。该循环作为一个独立的脚本工作,但是当在文件系统观察程序中使用该脚本时,它会在此行停止而不会出现任何错误:

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

无论 $ErrorActionPreference = "SilentlyContinue" 是否被注释掉,都会发生这种情况。我一直无法收集任何日志输出来查看为什么使用 Start-Transcript 或 Out-File 停止脚本。

我应该如何最好地收集有关脚本在到达此行后停止的原因的错误信息?

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

    $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
    }

【问题讨论】:

  • 您的帖子并不是一个明确的问题,但有几种暗示。我已经回答了一个问题,但请看一下stackoverflow.com/help/how-to-ask
  • 感谢您的意见。我试图重写问题描述并提供了一些应该更清楚的问题。

标签: powershell filesystemwatcher


【解决方案1】:

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

【讨论】:

  • 我赞成你的回答,但不幸的是,我的名声在我之前。我将使用 try/catch 将异常消息拉出并让您知道结果!
  • 我将“do while”循环转换为使用 try/catch 而不是 if 语句,并使用 $_.Exception.Message 和 $_.Exception.ItemName 来查看发生了什么。例外是我在独立运行脚本时通常会看到的情况,但 $ErrorActionPreference 会正常滚动。 if 语句是错误的方法......从这一点开始,我将使用 try/catch/finally 来获得更好的效果!谢谢您的帮助。 =) 我将发布包含这些详细信息和代码的新答案,但仍会推荐您的答案。
【解决方案2】:

根据 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)

【讨论】:

    猜你喜欢
    • 2016-01-15
    • 1970-01-01
    • 2017-04-18
    • 2011-09-19
    • 2022-11-10
    • 2020-05-29
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多