1

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 を処理し、成功するまで黙って再試行するように、コードを強化したいと考えています。助言がありますか?

4

3 に答える 3

1

PowerShellでのCOMサポートは100%信頼できるわけではありません。しかし、本当の問題はiTunes自体だと思います。アプリケーションとCOMモデルは、このタイプの管理用に設計されたものではありません、IMO。そうは言っても、スクリプトにトラップを実装することができます。例外が発生した場合、スクリプトを数秒間スリープさせることができます。

于 2008-10-08T11:09:26.697 に答える
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これはとのデフォルト値を使用するため、100 回$maxRetries呼び出しを試行し、試行$Library.searchごとに 2 秒待機します。すべての再試行が失敗した場合、最後のエラーが外側のスコープに伝播します。に設定$ErrorActionPreferenceStopて、スクリプトがそれ以上ステートメントを実行しないようにすることができます。

于 2008-10-19T22:39:51.323 に答える
0

問題の一部は、 $Track.name の評価方法にある可能性があります。$($Track.name) を使用して、名前を完全に評価するように強制することができます。

あなたが試すかもしれないもう1つのことは、 new-object コマンドで -strict パラメータを使用することです/

于 2008-10-09T17:53:12.167 に答える