2013-08-01 144 views
3

我開發了這個腳本,將Sitecore工作流應用於整個項目,而無需通過GUI手動點擊。我對它的工作效果非常滿意,但速度很慢。這裏是腳本:爲什麼此PowerShell腳本如此緩慢?我如何加快速度?

Import-Module 'C:\Subversion\CMS Build\branches\1.2\sitecorepowershell\Sitecore.psd1' 

# Hardcoded IDs of workflows and states 
$ContentApprovalWfId = "{7005647C-2DAC-4C32-8A09-318000556325}"; 
$ContentNoApprovalWfId = "{BCBE4080-496F-4DCB-8A3F-6682F303F3B4}"; 
$SettingsWfId = "{7D2BA7BE-6A0A-445D-AED7-686385145340}"; 

#new-psdrive *REDACTED* 

set-location m-rocks: 

function ApplyWorkflows([string]$path, [string]$WfId) { 
    Write-Host "ApplyWorkflows called: " $path " - " $wfId; 
    $items = Get-ChildItem -Path $path; 
    $items | foreach-object { 
     if($_ -and $_.Name) { 
      $newPath = $path + '\' + $_.Name; 
      $newPath; 
     } else { 
      Write-host "Name is empty."; 
      return; 
     } 

     if($_.TemplateName -eq "Folder" -or $_TemplateName -eq "Template Folder") { 
      # don't apply workflows to pure folders, just recurse 
      Write-Host $_.Name " is a folder, recursing."; 
      ApplyWorkflows $newPath $wfId; 
     } 
     elseif($_.TemplateName -eq "Siteroot" -or $_.TemplateName -eq "InboundSiteroot") { 
      # Apply content-approval workflow 
      Set-ItemProperty $newPath -name "__Workflow" $ContentApprovalWfId; 
      Set-ItemProperty $newPath -name "__Default workflow" $ContentApprovalWfId; 

      # Apply content-no-approval workflow to children 

      Write-Host $_.Name " is a siteroot, applying approval workflow and recursing."; 
      ApplyWorkflows $newPath $ContentNoApprovalWfId; 
     } 
     elseif($_.TemplateName -eq "QuotesHomePage") { 
      # Apply settings workflow to item and children 

      Write-Host $_.Name " is a quotes item, applying settings worfklow recursing."; 

      Set-ItemProperty $newPath -name "__Workflow" $SettingsWfId; 
      Set-ItemProperty $newPath -name "__Default workflow" $SettingsWfId; 

      ApplyWorkflows $newPath $SettingsWfId; 
     } 
     elseif($_.TemplateName -eq "Wildcard") 
     { 
      Write-Host $_.Name " is a wildcard, applying workflow (and halting)."; 
      Set-ItemProperty $newPath -name "__Workflow" $ContentApprovalWfId; 
      Set-ItemProperty $newPath -name "__Default workflow" $ContentApprovalWfId; 
     } 
     elseif($_ -and $_.Name) { 
      # Apply passed in workflow and recurse with passed in workflow 
      Write-Host $_.Name " is a something else, applying workflow and recursing."; 
      Set-ItemProperty $newPath -name "__Workflow" $WfId; 
      Set-ItemProperty $newPath -name "__Default workflow" $WfId; 

      ApplyWorkflows $newPath $wfId; 
     } 
    } 
} 

ApplyWorkflows "sitecore\Content\" $ContentNoApprovalWfId; 

它處理一個項目在不到一秒鐘。其進展有一些暫停 - 有證據表明,這是Get-ChildItem返回很多項目。有很多我想嘗試的事情,但它仍然針對我們的某個網站運行。已經有大約50分鐘了,看起來可能完成了50%,也許更少。看起來它的工作範圍很廣,所以很難掌握完成的工作和不完成的工作。

那麼是什麼讓我失望?

它是路徑構建和檢索嗎?我試圖通過$_$_.Name來獲取當前項目上的子項,但它始終在當前工作目錄中查找,該目錄是根目錄,並且無法找到項目。每次遞歸都會更改目錄嗎?

輸出是否讓它停滯不前?沒有輸出,我不知道它在哪裏,或者它還在工作。有沒有其他方式可以指出它在哪裏,它做了多少等等?

有更好的方法,我只是使用Get-ChildItem -r與過濾器設置和循環通過那些?如果是這樣,首先嚐試將第一個腳本中的一些條件合併到過濾器集合中,將會非常感激。我是PowerShell的新手,所以我確信在我的代碼中有一兩個或兩個以上的改進。

即使沒有孩子,我總是調用遞歸位嗎?這裏的內容樹非常寬廣,有很多沒有孩子的樹葉。什麼將是一個很好的檢查是否存在子項目?

最後,我們擁有的PowerShell提供程序(PSP)尚未完成。它似乎沒有Get-Item的工作實現,這就是爲什麼一切都幾乎完全用Get-ChildItem編寫的原因。我們的Sitecore.Powershell.dll說它是版本0.1.0.0。升級那些幫助?有新的嗎?

編輯:它終於完成了。我對輸出進行了計數,並提出了1857個項目,花費了大約85分鐘的時間,平均每分鐘21項。比我想象的慢,甚至...

編輯:我的第一次運行是在PowerShell 2.0上,使用Windows PowerShell ISE。我還沒有嘗試Sitecore PowerShell插件模塊或社區。我甚至不知道它直到昨天才存在:-)

升級到PowerShell 3.0後,我嘗試了另一次運行。從本地啓動 - 從我的筆記本電腦運行腳本,連接到遠程服務器 - 沒有明顯差異。我在主機上安裝了PowerShell 3.0,並從那裏運行腳本,發現速度可能會提高20-30%。所以這不是我希望會發生的銀彈 - 我需要一個數量級或兩個數值的改進來使這個東西,我不必照顧和分批運行。我現在正在使用下面的精確答案建議的一些實際的腳本改進。我會回覆對我有用的東西。

+0

參見[這裏](http://blogs.msdn.com/b/powershell/archive/2009/11/04/why-is-get- childitem那麼slow.aspx)。 –

+0

在類似的說明@AnsgarWiechers的說法中,您可能會發現它在Powershell 3上更快。您使用哪個版本? –

+0

@zespri使用[$ psversiontable.psversion] [這個問題](http://stackoverflow.com/questions/1825585/how-to-determine-what-version-of-powershell-is-installed),它說我在2.0.-1.-1,嘿。升級時間。 –

回答

5

就我個人而言,我認爲如果您開始在Rocks上使用社區PowerShell實現,您將獲得最大的提升。

讓我解釋一下爲什麼。

您正在遍歷整棵樹,這意味着您必須訪問您的分支中的每個節點,這意味着它必須被讀取並至少在岩石Web服務上傳播一次。 然後每個屬性保存是另一個web服務調用。

我已經在社區控制檯中運行腳本,並花費了大約25秒3724個項目。 (我已經刪除了修改,因爲這些值與我的系統無關)。

一個簡單

Get-ChildItem -recurse 

在我的3724項樹用了11秒的社區控制檯VS在岩石實施48秒。

,你可以在社區實現你的腳本中使用附加的調整將是使用Sitecore的查詢,如:

get-item . -Query '/sitecore/content/wireframe//*[@@TemplateName="Template Folder"]' 

只發送這些項目給你的函數

這都不意味着岩石控制檯是不正確的,它只是意味着岩石控制檯的設計選擇,他們的目標是不同的。

您可以找到社區控制檯的位置: http://bit.ly/PsConScMplc

+0

它是有道理的,遍歷網絡是緩慢的。我在等待腳本完成時發現了這個插件。我仍然試圖掌握它的工作原理。看起來我需要將它作爲一個軟件包安裝在我想要運行的環境中 - 是嗎?我們的部署過程完全取代了我們服務器上的所有'.dll' - Sitecore和我們的 - 。會消滅這樣安裝的軟件包嗎?我想通過包添加到內容樹的項目將會持續。我是否需要將某些PowerShell dll或某些源代碼管理軟件放入源代碼管理中? –

+0

安裝軟件包將帶來所有必需的位。如果您的數據庫中部署了控制檯項目,則可以簡單地複製包中的文件。 (如果你解壓縮它只是把文件夾裏的文件整合到內部版本中,除此之外它會使用服務器上部署的PowerShell。 至於你如何創建和使用你的腳本:你可以使用直接顯示在開始菜單中的交互式終端,或者最好是可以在開始菜單的「開發工具」子菜單中找到的PowerShell ISE。 –

+0

在相關說明中,您最喜歡的學習查詢的參考是什麼你在那裏得到項目的人使用的語法?在尋找一個指南/初學者教程,我只能找到奇怪的一次性提示和技巧類型的文章,沒有什麼全面的,真的能夠學習它 –

0

我看到的最明顯的問題是,你是遍歷文件兩次每個函數的調用:

function ApplyWorkflows([string]$path, [string]$WfId) { 
    Write-Host "ApplyWorkflows called: " $path " - " $wfId; 


    # this iterates through all files and assigns to $items 
    $items = Get-ChildItem -Path $path; 

    # this iterates through $items for a second time 
    $items | foreach-object { # foreach-object is slower than for (...) 

另外,配管的foreach對象比使用傳統的for關鍵字慢。

+0

那我該如何解決這個問題?直接將'Get-ChildItem'調用到'foreach'?我會如何做一個for? –

+0

其實,['for'可能有時非常慢,與'foreach'聲明相反](http://stackoverflow.com/a/17877292/73070)。但是,這些結果可能並不普遍。 – Joey

1

請參閱this blog post其中foreach-object cmdlet和foreach語句之間存在明顯差異。

你可以加快它的時候,你管的get-childitem用foreach對象:

get-childitem . | foreach-object { ApplyWorkflow($_) } 

這將導致由get-childitem返回的每個對象將被立即傳遞給在管道下面的步驟,以便您將只處理它們一次。此操作還應該可以防止閱讀所有孩子的長時間停頓。

另外,你可以得到所有的項目遞歸,並通過模板過濾它們,然後應用適當的工作流程,如:

get-childitem -recurse . | where-object { $_.TemplateName -eq "MyTemplate"} | foreach-object { ApplyWorkflowForMyTemplate($_) } 
get-childitem -recurse . | where-object { $_.TemplateName -eq "MySecondTemplate"} | foreach-object { ApplyWorkflowForMySecondTemplate($_) } 

不過我寧可不要指望這個腳本在幾秒鐘內想運行。最後,你要瀏覽整個內容樹。

最後你在使用什麼庫?這是Sitecore Powershell Console(dll的名字聽起來很熟悉)?有更新的版本添加了許多新功能。

+0

感謝您的代碼提示。我用PS庫信息編輯了我的問題。我將研究Sitecore Powershell控制檯。它是否依賴於託管機器上安裝的Powershell版本?或者它是否帶有最新/最好的(3.0,正確的?)版本? –

+0

控制檯只執行整合位,在上下文內和Sitecore的進程內運行已安裝的PowerShell。這可以讓它更快。 –

相關問題