2017-04-05 79 views
1

我經常寫的是需要接受管道喜歡的功能:PowerShell管道迭代

function Invoke-ExchangeHubChecks 
{ 
    [cmdletbinding()] 
    param 
    (
     [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 
     [object[]]$oServersToTest, 
     [int]$QueueWarnThreshold = 50, 
     [int]$QueueFailThreshold = 100 

    ) 
    begin 
    { 
     $oHubTests = @() 
     $c=0 
    } 
    Process 
    { 
     $c++ 
     $Server = $oServersToTest[0] 

     $oHubTests += [pscustomobject]@{ 
      Identity = $server.Identity 
      Queue = "blah" 
      Count = $c 
     } 
    } 
    end 
    { 
     $oHubTests 
    } 
} 
    end 
    { 
     $oHubTests 
    } 
} 

我經常看到的代碼片段與工藝塊內一個foreach。我的理解是,進程塊取代了對foreach塊的需求(在大多數情況下)。

我需要爲輸入對象「$ oServersToTest」添加一個「過濾器」。我用「凡客體」創建過濾器:

$Server = $oServersToTest[0] | Where-Object {$_.IsHub} 

然而,由於它遍歷集合,它補充說,不要在where子句自定義對象匹配的對象,由$ C證明:

輸出:

Identity Queue Count 
-------- ----- ----- 
Server01 blah  1 
Server02 blah  2 
Server03 blah  3 
Server04 blah  4 
Server05 blah  5 
      blah  6 
      blah  7 
Server06 blah  8 
Server07 blah  9 
Server08 blah  10 
Server09 blah  11 
Server10 blah  12 
      blah  13 
      blah  14 

這是一個例子,其中我必須使用處理塊內一個foreach:

Process 
{ 
    $c++ 
    #$Server = $oServersToTest[0] | Where-Object{$_.IsHubServer} 
    $TestResult = @() 
    $oServersToTest | Where-Object {$_.IsHubServer} | Foreach-object{ 
     $TestResult += [pscustomobject]@{ 
      Identity = $_.Identity 
      Queue = "blah" 
      Count = $c 
     } 
    } 

    $oHubTests += $TestResult 
} 
End 
{ 
    $oHubTests 
} 

哪個有效,但爲什麼這個工作,而不是其他方式?對我來說,這是工作的兩倍。

(Powershell的5.0)

TIA

+1

在大多數情況下,PROCESS過程中的'ForEach'允許過濾器/函數既可以作爲cmdlet('Do-MyStuff-計算機名稱A,B,C')使用,也可以作爲過濾器使用管道('Retrieve-Computers | Do-MyStuff')。這是有效的,因爲如果'$ ComputerName'被聲明爲'[String []]'並且只傳遞一個計算機名稱,它將被強制轉換爲只有一個元素的數組。 –

回答

0

我會用一個foreach()迴路process塊內。

由於Jeff Zeitlin points out,這也允許您支持處理命名參數和流水線。

之所以使用foreach()超過ForEach-Object有三層:

  1. 性能:
    當輸入收集已經在存儲器(它是在這兩種情況下),從隱式參數綁定將開銷使ForEach-Objectforeach()
  2. 可讀性:
    IMO,具有命名的變量(如$Server)使腳本更具可讀性和你避免與嵌套混亂10項Where-Object條款環路
  3. 功能裏面:
    隨着純醇」 foreach(),你得到像breakcontinue自由快速流動的控制選項。

process { 
    $oHubTests += foreach($server in $oServersToTest |Where-Object {$_.IsHubServer}){ 
     $c++ 
     [pscustomobject]@{ 
      Identity = $server.Identity 
      Queue = "blah" 
      Count = $c 
     } 
    } 
} 

如果你的小命令做的唯一事情就是把輸入和構建相應的[pscustomobject]的,那我就徹底斷絕了$oHubTests部分,並且只輸出對象,因爲它們流經:

function Invoke-ExchangeHubChecks 
{ 
    [CmdletBinding()] 
    param 
    (
     [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 
     [object[]]$oServersToTest, 
     [int]$QueueWarnThreshold = 50, 
     [int]$QueueFailThreshold = 100 

    ) 
    begin { 
     $c=0 
    } 
    process { 
     foreach($server in $oServersToTest |Where-Object {$_.IsHubServer}){ 
      $c++ 
      [pscustomobject]@{ 
       Identity = $server.Identity 
       Queue = "blah" 
       Count = $c 
      } 
     } 
    } 
} 
0

您正在爲我解決一個最複雜的PowerShell設計結構。創建一個cmdlet,該cmdlet可以處理作爲參數或每個項目提供的對象數組,作爲輸入到cmdlet中的對象。例如,do-something -input $items$items | do-something

進程塊主要用於cmdlet接受管道值時。它不會像你想象的那樣取代for循環。儘管這不是百分百準確的,但管道已經對收集進行了隱式循環,但這是一個不同的故事。爲了簡單起見,我將繼續以某種不準確的陳述。

在這種情況下,begin,processend允許您控制在管道或虛構環路的每個部分發生的情況。 Beforeend只執行一次,可用於初始化和最終化。在上面的例子中,首先執行begin,然後process爲從集合中傳送的每個項目,然後是end。但是,如果集合用作正常參數,那麼它的內部爲begin,process,然後是end

我知道這很複雜,但試圖用一個do-something實現可視化,該實現只是向主機寫入正在發生的事情。

我在開發MarkdownPS時必須瞭解這個順序。檢查此example和根用法的示例。 Get-ChildItem | Select-Object Name | New-MDList。僅供參考,最後一個例子是我在這個答案中使用的不準確陳述的證明。