Question

J'utilise PowersHell pour automatiser iTunes, mais la gestion des erreurs et l'attente de la gestion des objets COM n'est pas optimale.

Exemple de code

#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 

Allez sur iTunes et faites quelque chose qui fasse apparaître un message: dans mon cas, je vais dans le Party Shuffle et je reçois une bannière "Party Shuffle automatiquement, bla bla ....". avec un " ne pas afficher " message.

À ce stade, si l'exécution du script effectue cette opération à plusieurs reprises:

+      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

Si vous attendez d'avoir une boîte de dialogue avant d'exécuter l'exemple, vous obtiendrez cette information à plusieurs reprises:

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

Ce sera parce que le descripteur $ Library est invalide.

Si mon exemple faisait quelque chose d'important, comme la conversion de pistes puis la suppression des anciennes, le fait de ne pas traiter correctement l'erreur peut être fatal pour les pistes dans iTunes. Je souhaite renforcer le code pour qu'il gère l'occupation d'iTunes et réessaye en silence jusqu'à ce qu'il réussisse. Des suggestions?

Était-ce utile?

La solution

Voici une fonction pour relancer les opérations, en pause entre les échecs:

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
}

Pour la première erreur de votre exemple, vous pouvez modifier la boucle interne foreach comme suit:

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

Ceci utilise les valeurs par défaut pour $ wait et $ maxRetries . Il tentera donc d'appeler $ Library.search 100 fois, en attente. 2 secondes entre chaque essai. Si toutes les tentatives échouent, la dernière erreur se propage à l'étendue externe. Vous pouvez définir $ ErrorActionPreference sur Arrêter pour empêcher le script d'exécuter d'autres instructions.

Autres conseils

La prise en charge de COM dans PowerShell n’est pas fiable à 100%. Mais je pense que le vrai problème est iTunes lui-même. L'application et le modèle COM n'ont pas été conçus, IMO, pour ce type de gestion. Cela dit, vous pouvez implémenter un piège dans votre script. Si une exception est générée, le script peut rester en veille quelques secondes.

Une partie de votre problème pourrait être liée à l'évaluation de $ Track.name. Vous pouvez essayer de le forcer à évaluer complètement le nom en utilisant $ ($ Track.name).

Vous pouvez également essayer d'utiliser le paramètre -strict avec votre commande new-object /

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top