RPC_E_SERVERCALL_RETRYLATER durante automação powershell
-
05-07-2019 - |
Pergunta
Estou usando o PowerShell para automatizar o iTunes, mas encontrar o tratamento de erros / aguardando com manipulação de objetos para ser abaixo do ideal.
código Exemplo
#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
Vá para o iTunes e fazer algo que torna aparecer uma mensagem - no meu caso eu ir para o Party Shuffle e fico com uma faixa "Party Shuffle automaticamente blá blá ...." com um "Não mostrar" mensagem .
Neste ponto, se executar o script vai fazer isso várias vezes:
+ 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 você esperou até que você tivesse uma caixa de diálogo antes de executar o exemplo, então em vez disso você vai ter isso várias vezes:
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)) {
Isso vai ser porque o identificador $ Biblioteca é inválido.
Se o meu exemplo foi fazendo algo importante - como converter faixas e, em seguida, apagar os antigos, não lidar com o erro corretamente poderia ser fatal para as faixas no iTunes. Eu quero endurecer-se o código para que ele lida com iTunes estar ocupado e silenciosamente repetir até que tenha sucesso. Alguma sugestão?
Solução
Aqui está uma função para operações de repetição, fazendo uma pausa entre falhas:
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
}
Para o primeiro erro no seu exemplo, você poderia alterar o loop foreach
interior como esta:
$FoundTracks = retry { $Library.search( "$Track.name", 5 ) }
foreach ($FoundTrack in $FoundTracks) { ... }
Este utiliza os valores padrão para $wait
e $maxRetries
, por isso vai tentar $Library.search
chamada 100 vezes, esperando 2 segundos entre cada tentativa. Se todas as tentativas falharem, o último erro irá propagar para o escopo externo. Você pode definir $ErrorActionPreference
para Stop
para impedir que o script de executar quaisquer outras declarações.
Outras dicas
suporte COM no PowerShell não é 100% confiável. Mas eu acho que a verdadeira questão é próprio iTunes. O modelo de aplicação e COM não foi projetado, IMO, para este tipo de gestão. Dito isto, você poderia implementar uma armadilha em seu script. Se uma exceção é lançada, você poderia ter o sono de script por alguns segundos.
Parte do seu problema pode ser na forma como $ Track.name está sendo avaliada. Você poderia tentar forçá-lo a avaliar completamente o nome usando $ ($ Track.name).
Uma outra coisa que você pode tentar é usar o parâmetro -strict com o seu novo objeto de comando /