2013-05-20 2 views
5

간단한 질문 : 누구나 ForEach-Object의 -RemainingScripts 매개 변수에 대한 자세한 정보가 있습니까?PowerShell : ForEach-Object의 신비한 -RemainingScripts 매개 변수

긴 질문 :

나는 지난 주에서 PowerShell을 배우기 시작하고 좀 더 자세한 내용은 각 사람 cmdlet을 통해거야.

Get-ChildItem | foreach -Begin { "block1"; 
    $fileCount = $directoryCount = 0} -Process { "block2"; 
    if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}} -End { 
    "block3"; "$directoryCount directories and $fileCount files"} 

결과가 예상된다 "블록 1"과 "BLOCK3"1 시간 "블록 2"가 반복되는 공공 문서를 바탕으로, 우리를 ForEach가-Object가 시작 - 프로세스 엔드 블록을 같이 할 수 있습니다 알고 전달 된 각 항목 및 dir 수/파일 수는 모두 정확합니다. 여태까지는 그런대로 잘됐다. foreach 문에 전달

Get-ChildItem | foreach { "block1" 
    $fileCount = $directoryCount = 0}{ "block2"; 
    if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}{ 
    "block3"; "$directoryCount directories and $fileCount files"} 

그냥 3 ScriptBlocks :

지금, 어떤 흥미로운 것은 다음과 같은 명령은 작품과 정확히 같은 결과를 제공한다. 매뉴얼을 기반으로, 첫 번째는 -Process (Position 1)로 이동합니다. 그러나 나머지 2는 어때요? 매뉴얼에 따르면 "위치 2"의 매개 변수는 없습니다. 그래서 Trace-Command로 돌아가서 나중에 2 개의 스크립트 블록이 실제로 RemainingScripts에 "IList with 2 elements"라는 사실을 알게되었습니다.

BIND arg [$fileCount = $directoryCount = 0] to parameter [Process] 
BIND arg [System.Management.Automation.ScriptBlock[]] to param [Process] SUCCESSFUL 
BIND arg [System.Collections.ArrayList] to parameter [RemainingScripts] 
BIND arg [System.Management.Automation.ScriptBlock[]] to param [RemainingScripts] SUCCESSFUL 

그래서 나는이에 명령을 변경하는 경우 :

# No difference with/without the comma "," between the last 2 blocks 
Get-ChildItem | foreach -Process { "block1" 
    $fileCount = $directoryCount = 0} -RemainingScripts { "block2"; 
    if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}},{ 
    "block3"; "$directoryCount directories and $fileCount files"} 

아직 정확히 같은 결과를.

그래서 3 개의 명령 모두 동일한 결과를 나타냅니다. 흥미로운 질문이 제기됩니다. 나중에 두 명령 (암시 적으로)이 모두 -Process로 지정되었지만 ForEach-Object는 놀랍게도 -Process 인수를 "-Begin"으로 사용합니다. (스크립트 블록은 처음에 한 번 실행됩니다).

이 실험은 제안 : 첫 번째는 -process 간다하더라도

  1. -RemainingScripts 매개 변수가
  2. 3 개 블록에서 전달되는 모든 언 바운드 ScriptBlocks를 취할 것입니다, 나중에 실제로 "시작하기"로 사용됩니다 나머지 2 개는 "프로세스"및 "종료"가됩니다.

그래도 위의 내용은 모두 내 추측입니다. 내 추측을 뒷받침하는 문서를 찾지 못했습니다

결국, 짧은 질문으로 돌아갑니다 :) 누구나 ForEach-Object의 -RemainingScripts 매개 변수에 대한 자세한 정보가 있습니까?

감사합니다.

답변

3

난 당신이 다음 명령을 실행합니다.

을 여러 ScriptBlocks가 전달 될 때 -RemainingScripts 매개 변수의 행동에 대답 할 자신이 지금 더 연구를 느끼고 그 결과를 검사 않았다 신중하게, 당신은 그 패턴을 발견 할 것입니다. 아주 간단하지는 않지만 알아 내기가 어렵지 않습니다.

1..5 | foreach { "process block" } { "remain block" } 
1..5 | foreach { "remain block" } -Process { "process block" } 
1..5 | foreach { "remain block" } -End { "end block" } -Process { "process block" } -Begin { "begin block" } 
1..5 | foreach { "remain block 1" } -End { "end block" } -Process { "process block" } { "remain block 2" } 
1..5 | foreach { "remain block 1" } { "remain block 2" } -Process { "process block" } -Begin { "begin block" } 
1..5 | foreach { "remain block 1" } { "remain block 2" } -Process { "process block" } { "remain block 3" } 
1..5 | foreach { "process block" } { "remain block 1" } { "remain block 2" } -Begin { "begin block" } 
1..5 | foreach { "process block" } { "remain block 1" } { "remain block 2" } { "remain block 3" } 

여기 패턴은 무엇입니까? 전달 하나를 ScriptBlock있을 때

  • 가 : 정확히 2 ScriptBlocks 3 개 가능한 조합

      가, 전달되는 쉬운, 그냥 -process 간다 (가장 일반적으로 사용)

    1. & -Begin - 프로세스 -> - 프로세스
    2. & -end
    3. 를 지정한 실행 -> 를 지정한 실행 -
    4. - 프로세스 & -RemainingScripts 우리가이 두 문장 실행하면 RemainingScripts이 프로세스

을하게하면서> 프로세스가 시작됩니다 : 당신은 발견 할 것이다으로

1..5 | foreach { "process block" } { "remain block" } 
1..5 | foreach { "remain block" } -Process { "process block" } 

# Both of them will return: 
process block 
remain block 
remain block 
remain block 
remain block 
remain block 

이 단지 특별하다 다음 테스트 케이스의 경우 :

  • 2 개 이상의 ScriptBlocks가 전달 된 경우 이 워크 플로 :

    1. 지정된대로 모든 스크립트 블록을 바인딩합니다 (시작, 프로세스, 종료). 나머지 스크립트 블록은 RemainingScripts로 이동
    2. 모든 스크립트를 다음과 같이 주문하십시오. Begin> Process> Remaining> End
    3. 주문 결과는 ScriptBlocks의 모음입니다. 바인딩되지 않습니다/종료를 시작, 그냥 무시의는이 컬렉션을 OrderedScriptBlocks

      • 을 부르 자
    4. (내부적으로) OrderedScriptBlocks

      • OrderedScriptBlocks [기반으로 다시 바인드 매개 변수 0]이 시작됨
      • OrderedScriptBlocks [1 ..

        : 2]가 프로세스
      • OrderedScriptBlocks [-1] (마지막)는 종료

이의이

1..5 | foreach { "remain block 1" } { "remain block 2" } -Process { "process block" } { "remain block 3" } 

주문 결과이 예제를 보자됩니다된다

{ "process block" } # new Begin 
{ "remain block 1" } # new Process 
{ "remain block 2" } # new Process 
{ "remain block 3" } # new End 

이제 실행 결과는 다음과 같습니다. 완전히 예측 가능 :

process block 
remain block 1 
remain block 2 
remain block 1 
remain block 2 
remain block 1 
remain block 2 
remain block 1 
remain block 2 
remain block 1 
remain block 2 
remain block 3 

이것은 Remainscript의 숨겨진 비밀이며 이제 우리는 ForEach-Object의 내부 동작을 더 잘 이해합니다!

아직도 추측을 뒷받침 할 문서가 없다는 것을 인정해야합니다. (내 잘못이 아닙니다!)하지만이 테스트 사례는 설명 된 동작을 설명하기에 충분해야합니다.

1

여기에 자세한 내용이 나와 있습니다. ValueFromRemainingArguments은 true로 설정되어 추측이 정확합니다.

help ForEach-Object 

-RemainingScripts <ScriptBlock[]> 
    Takes all script blocks that are not taken by the Process parameter. 

    This parameter is introduced in Windows PowerShell 3.0. 

gcm ForEach-Object | select -exp parametersets 

Parameter Name: RemainingScripts 
    ParameterType = System.Management.Automation.ScriptBlock[] 
    Position = -2147483648 
    IsMandatory = False 
    IsDynamic = False 
    HelpMessage = 
    ValueFromPipeline = False 
    ValueFromPipelineByPropertyName = False 
    ValueFromRemainingArguments = True 
    Aliases = {} 
    Attributes = 
    System.Management.Automation.ParameterAttribute 
    System.Management.Automation.AllowEmptyCollectionAttribute 
    System.Management.Automation.AllowNullAttribute 
+0

감사합니다. Andy, 당신은 포인트 # 1을 답했습니다 : "-RemainingScripts 매개 변수는 언 바운드 ScriptBlocks를 모두 가져 오지만 포인트 # 2는 설명하지 않았습니다."첫 번째 블록은 처리되지만, 블록 3 개가 전달 될 때 ... "이것은 실제로이 질문의 주된 이유입니다. 나는 더 많은 조사를했고 #point 2에 답할 수 있다고 생각합니다. 그러나 답과 매개 변수를 검사하는 기술에 감사드립니다. 죄송합니다. 매우 유용하다고해도 답변에 투표 할 수있는 권한이 없습니다. –

관련 문제