質問

iTunesを自動化するためにPowersHellを使用していますが、エラー処理/ 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がビジーであることを処理し、成功するまで静かに再試行するようにコードを強化します。提案はありますか?

役に立ちましたか?

解決

操作を再試行し、失敗の合間に一時停止する関数を次に示します。

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 に設定して、スクリプトがそれ以上ステートメントを実行しないようにすることができます。

他のヒント

PowerShellでの

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

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

もう1つの方法は、-strictパラメーターをnew-objectコマンドで使用することです

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top