2008-10-08 36 views
1

我正在使用PowersHell來自動化iTunes,但發現錯誤處理/等待com對象處理不夠理想。在PowerShell自動化期間RPC_E_SERVERCALL_RETRYLATER

示例代碼

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

這將是因爲$庫句柄無效。

如果我的例子做了一些重要的事情 - 比如轉換曲目然後刪除舊曲目,不正確處理錯誤可能會對iTunes中的曲目造成致命的影響。 我想強化代碼,以便它可以處理iTunes正在忙碌的事情,並會默默重試,直到成功爲止。有什麼建議麼?

回答

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$maxRetries,因此它會嘗試呼叫$Library.search 100次,每次嘗試之間等待2秒鐘。如果所有重試失敗,則最後的錯誤將傳播到外部作用域。您可以將$ErrorActionPreference設置爲Stop以防止腳本執行任何其他語句。

1

PowerShell中的COM支持不是100%可靠的。但我認爲真正的問題是iTunes本身。對於這種類型的管理,應用程序和COM模型並未設計爲IMO。也就是說,你可以在你的腳本中實現一個陷阱。如果發生異常,您可以讓腳本休眠幾秒鐘。

+0

不幸的是,它不會像睡覺一樣簡單,因爲我的真實腳本根據對象結果執行大量嵌套操作。我想我可以把所有東西都放到它們自己的功能上,並把陷阱包裹在它們周圍,但是......我希望能夠做一個簡單的foreach工作方式。 – 2008-10-10 07:11:27

0

問題的一部分可能在於如何評估$ Track.name。你可以嘗試強制它使用$($ Track.name)來完全評估名稱。你可以嘗試用你的新對象命令的-strict參數

的另一件事/

+0

不幸的是-strict沒有幫助,$ track.name是空的,因爲$ library.tracks可能是空的。謝謝。 – 2008-10-10 06:58:42