【问题标题】:RPC_E_SERVERCALL_RETRYLATER during powershell automationpowershell 自动化期间的 RPC_E_SERVERCALL_RETRYLATER
【发布时间】:2008-10-20 06:39:51
【问题描述】:

我正在使用 PowersHell 来自动化 iTunes,但发现错误处理/等待 com 对象处理不是最佳的。

示例代码

#Cause an RPC error
$iTunes = New-Object -ComObject iTunes.Application
$LibrarySource = $iTunes.LibrarySource
# Get "playlist" objects for main sections
foreach ($PList in $LibrarySource.Playlists)
{
  if($Plist.name -eq "Library") {
    $Library = $Plist
  }
}
do {
  write-host -ForegroundColor Green "Running a loop"
  foreach ($Track in $Library.Tracks)
  {
     foreach ($FoundTrack in $Library.search("$Track.name", 5)) {
       # do nothing... we don't care...
       write-host "." -nonewline
     }
  }
} while(1) 
#END 

进入 iTunes 并做一些事情,让它弹出一条消息 - 在我的情况下,我进入派对随机播放,我得到一个横幅“派对随机播放自动等等等等……”和一条“不显示”消息.

此时如果运行脚本会重复执行此操作:

+      foreach ($FoundTrack in $Library.search( <<<< "$Track.name", 5)) {
Exception calling "Search" with "2" argument(s): "The message filter indicated
that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVER
CALL_RETRYLATER))"
At C:\Documents and Settings\Me\My Documents\example.ps1:17 char:45
+      foreach ($FoundTrack in $Library.search( <<<< "$Track.name", 5)) {
Exception calling "Search" with "2" argument(s): "The message filter indicated
that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVER
CALL_RETRYLATER))"
At C:\Documents and Settings\Me\My Documents\example.ps1:17 char:45

如果您等到出现对话框后才运行示例,那么您将反复得到这个:

Running a loop
You cannot call a method on a null-valued expression.
At C:\Documents and Settings\Me\example.ps1:17 char:45
+      foreach ($FoundTrack in $Library.search( <<<< "$Track.name", 5)) {

那是因为 $Library 句柄无效。

如果我的示例正在做一些重要的事情——比如转换曲目,然后删除旧的,不正确处理错误可能对 iTunes 中的曲目是致命的。 我想强化代码,以便它处理 iTunes 繁忙,并静默重试,直到成功。有什么建议吗?

【问题讨论】:

    标签: powershell itunes


    【解决方案1】:

    这是一个重试操作的函数,在失败之间暂停:

    function retry( [scriptblock]$action, [int]$wait=2, [int]$maxRetries=100 ) {
      $results = $null
    
      $currentRetry = 0
      $success = $false
      while( -not $success ) {
        trap {
          # Set status variables at function scope.
          Set-Variable -scope 1 success $false
          Set-Variable -scope 1 currentRetry ($currentRetry + 1)
    
          if( $currentRetry -gt $maxRetries ) { break }
    
          if( $wait ) { Start-Sleep $wait }
          continue
        }
    
        $success = $true
        $results = . $action
      }
    
      return $results
    }
    

    对于示例中的第一个错误,您可以像这样更改内部 foreach 循环:

    $FoundTracks = retry { $Library.search( "$Track.name", 5 ) }
    foreach ($FoundTrack in $FoundTracks) { ... }
    

    这使用$wait$maxRetries 的默认值,因此它将尝试调用$Library.search 100 次,每次尝试之间等待2 秒。如果所有重试都失败,最后一个错误将传播到外部范围。您可以将$ErrorActionPreference 设置为Stop 以防止脚本执行任何进一步的语句。

    【讨论】:

      【解决方案2】:

      PowerShell 中的 COM 支持并非 100% 可靠。但我认为真正的问题是 iTunes 本身。应用程序和 COM 模型不是为这种类型的管理设计的,IMO。也就是说,您可以在脚本中实现陷阱。如果引发异常,您可以让脚本休眠几秒钟。

      【讨论】:

      • 不幸的是,它不会像睡觉那么简单,因为我的真实脚本会根据对象结果执行大量嵌套操作。我想我可以把所有东西都放到它们自己的函数中,并在它们周围设置陷阱,但是......呃......希望有一种简单的方法让 foreach 工作。
      【解决方案3】:

      您的部分问题可能在于如何评估 $Track.name。您可以尝试使用 $($Track.name) 强制它完全评估名称。

      您可能会尝试的另一件事是将 -strict 参数与您的 new-object 命令一起使用/

      【讨论】:

      • 不幸的是 -strict 没有帮助,并且 $track.name 为空,因为 $library.tracks 可能为空。谢谢。
      猜你喜欢
      • 2016-12-05
      • 2012-05-23
      • 1970-01-01
      • 2010-10-11
      • 2016-05-06
      • 2016-04-04
      • 2018-08-31
      • 2022-06-18
      • 1970-01-01
      相关资源
      最近更新 更多