Domanda

Sto usando PowersHell per automatizzare iTunes ma trovo che la gestione / attesa dell'errore nella gestione degli oggetti com sia meno che ottimale.

Codice di esempio

#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 

Vai su iTunes e fai qualcosa che lo fa apparire un messaggio - nel mio caso vado nel Party Shuffle e ricevo uno striscione " Party shuffle automaticamente blah blah .... " con un " Non visualizzare " messaggio.

A questo punto se l'esecuzione dello script lo farà ripetutamente:

+      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

Se hai aspettato di avere una finestra di dialogo prima di eseguire l'esempio, invece otterrai questo ripetutamente:

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)) {

Questo perché l'handle $ Library non è valido.

Se il mio esempio stava facendo qualcosa di importante, come convertire tracce e quindi eliminare quelle vecchie, non gestire correttamente l'errore potrebbe essere fatale per le tracce in iTunes. Voglio rafforzare il codice in modo che gestisca iTunes occupato e riproverà silenziosamente fino a quando non avrà successo. Qualche suggerimento?

È stato utile?

Soluzione

Ecco una funzione per riprovare le operazioni, facendo una pausa tra gli errori:

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
}

Per il primo errore nel tuo esempio, puoi modificare il ciclo foreach interno in questo modo:

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

Questo utilizza i valori predefiniti per $ wait e $ maxRetries , quindi tenterà di chiamare $ Library.search 100 volte, in attesa 2 secondi tra ogni tentativo. Se tutti i tentativi falliscono, l'ultimo errore si propaga all'ambito esterno. Puoi impostare $ ErrorActionPreference su Stop per impedire allo script di eseguire ulteriori dichiarazioni.

Altri suggerimenti

Il supporto COM in PowerShell non è affidabile al 100%. Ma penso che il vero problema sia iTunes stesso. L'applicazione e il modello COM non sono stati progettati, IMO, per questo tipo di gestione. Detto questo, potresti implementare una Trap nella tua sceneggiatura. Se viene sollevata un'eccezione, è possibile sospendere lo script per alcuni secondi.

Parte del problema potrebbe riguardare il modo in cui $ Track.name viene valutato. Puoi provare a forzarlo a valutare completamente il nome utilizzando $ ($ Track.name).

Un'altra cosa che potresti provare è usare il parametro -strict con il tuo comando new-object /

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top