2008-11-10 4 views
7

날짜가 지정된 시작일과 종료일 사이에 있으면 현재 개체를 파이프 라인으로 밀어 넣는 간단한 PowerShell 필터를 작성했습니다. 파이프 라인을 따라 내려 오는 개체는 항상 오름차순으로 정렬되므로 날짜가 지정된 종료 날짜를 초과하면 작업이 완료된 것으로 알고 파이프 라인에 업스트림 명령이 파이프 라인을 포기하도록 할 수 있습니다. 그것의 일을 끝낼 수 있습니다. 나는 아주 큰 로그 파일을 읽고 있는데 로그의 일부분 만 검사하기를 자주 원할 것입니다. 나는 이것이 가능하지 않다고 확신하지만 확신을 구하고 싶었다.필터 내에서 PowerShell 파이프 라인을 종료하거나 중지 할 수 있습니까?

답변

3

다운 스트림 명령에서 업스트림 명령을 중지 할 수 없습니다. 조건과 일치하지 않는 개체를 계속 필터링하지만 첫 번째 명령은 처리하도록 설정된 모든 것을 처리합니다.

해결 방법은 업스트림 cmdlet이나 함수/필터에 대한 필터링을 더 많이 수행하는 것입니다. 로그 파일로 작업하면 좀 더 복잡해질 수 있지만 원하지 않는 날짜를 걸러 내기 위해 Select-String과 정규식을 사용하는 것이 효과적 일 수 있습니다.

걸릴 줄 수와 패턴을 확인하기 위해 전체 파일을 읽을 위치를 모르는 경우가 아니면.

1

이러한 필터를 사용해보십시오. 첫 번째 개체 (첫 번째 n 요소)가 파이프 라인을 멈추게하고 변수에 저장합니다. 당신은 객체가 푸시 아웃되었지만 변수에 할당 될 수 없다면 변수의 이름을 전달해야합니다.

filter FirstObject ([string]$vName = '') { 
if ($vName) {sv $vName $_ -s 1} else {$_} 
break 
} 

filter FirstElements ([int]$max = 2, [string]$vName = '') { 
if ($max -le 0) {break} else {$_arr += ,$_} 
if (!--$max) { 
    if ($vName) {sv $vName $_arr -s 1} else {$_arr} 
    break 
} 
} 

# can't assign to a variable directly 
$myLog = get-eventLog security | ... | firstObject 

# pass the the varName 
get-eventLog security | ... | firstObject myLog 
$myLog 

# can't assign to a variable directly 
$myLogs = get-eventLog security | ... | firstElements 3 

# pass the number of elements and the varName 
get-eventLog security | ... | firstElements 3 myLogs 
$myLogs 

#################################### 

get-eventLog security | % { 
if ($_.timegenerated -lt (date 11.09.08) -and` 
    $_.timegenerated -gt (date 11.01.08)) {$log1 = $_; break} 
} 

# 
$log1 
+2

이 루프에서 작동하지 않습니다 휴식도 –

+0

@DavidGardiner을 루프를 중지 할 것'break'과 'CONTINUE'는 _not_ 종료하도록 설계 그들은 _loops_ (그리고'switch' 브랜치)에서 벗어납니다. 만약 엔 클로징 루프가 없다면, 함수가 종료된다는 것입니다. 이것은 부작용으로서 파이프 라인을 종료시킵니다. 그러나 둘러싸는 루프가 있다면, 그에 따라'break'와'continue'가 그에 따라 동작합니다. 이것은 예기치 않게 발생할 수 있습니다. 간단하지만 깨지기 쉽고 불편한 해결 방법은 [@ MaximumCookie 's answer] (http://stackoverflow.com/a/30943992/45375)에서와 같이 호출을 더미 루프로 감싸는 것입니다. – mklement0

2
당신의 정확한 요구 사항에 대해 확실

하지,하지만 당신은 심지어 파이프를 명중하기 전에 데이터를 필터링하는 쿼리를 사용할 수 있는지 확인하기 위해 Log Parser보기 위하여 당신의 시간 가치가있을 수 있습니다.

0

또 다른 옵션은 switch 문에 -file 매개 변수를 사용하는 것입니다. -file을 사용하면 한 번에 한 줄씩 파일을 읽을 수 있으며 나머지 파일은 읽지 않고 즉시 종료하려면 break을 사용할 수 있습니다.

switch -file $someFile { 
    # Parse current line for later matches. 
    { $script:line = [DateTime]$_ } { } 
    # If less than min date, keep looking. 
    { $line -lt $minDate } { Write-Host "skipping: $line"; continue } 
    # If greater than max date, stop checking. 
    { $line -gt $maxDate } { Write-Host "stopping: $line"; break } 
    # Otherwise, date is between min and max. 
    default { Write-Host "match: $line" } 
} 
4

그렇지 않으면 외부 루프 또는 중단 스크립트 실행을 중단 할 수있는 모든 작업과 파이프 라인을 중단 할 수 있습니다 모두 (예외를 던지기 같이). 그런 다음 솔루션은 파이프 라인을 루프로 감싸서 파이프 라인을 중지해야 할 경우 중단시킬 수 있습니다.예를 들어, 아래 코드는 파이프 라인에서 첫 번째 항목을 반환 한 후 외부 할-while 루프를 파괴함으로써 파이프 라인을 깰 :

do { 
    Get-ChildItem|% { $_;break } 
} while ($false) 

이 기능은이 같은 함수, 마지막 줄에 랩 할 수 있습니다 위와 같은 일을 수행 : - 불완전한 -

여기
function Breakable-Pipeline([ScriptBlock]$ScriptBlock) { 
    do { 
     . $ScriptBlock 
    } while ($false) 
} 

Breakable-Pipeline { Get-ChildItem|% { $_;break } } 
0

가의 Stop-Pipeline cmdlet을의 구현이 감사 this answer에서 적응, (PS v3의의 + 필요) :

#requires -version 3 
Filter Stop-Pipeline { 
    $sp = { Select-Object -First 1 }.GetSteppablePipeline($MyInvocation.CommandOrigin) 
    $sp.Begin($true) 
    $sp.Process(0) 
} 

# Example 
1..5 | % { if ($_ -gt 2) { Stop-Pipeline }; $_ } # -> 1, 2 

주의 사항 : 어떻게 작동하는지 완전히 이해하지는 않지만 근본적으로 Select -First의 파이프 라인을 조기에 중지 할 수있는 기능 (PS v3 +)을 활용합니다. 다운 스트림 cmdlet을 (파이프 라인 나중에 명령) 자신의 end 블록을 실행할 수있는 기회를 얻을하지 않습니다 그러나,이 경우 Select -First 파이프 라인을 종료하는 방법을 하나 개의 중요한 차이가있다.
따라서 응집하는 cmdlet (전체 입력 출력을 생성하기 전에 를 수신해야하는 것과 같은 Sort-Object, Group-ObjectMeasure-Object 등) 동일한 파이프 뒷부분에 배치 된 경우에 출력을 생성하지 않을 것이다; 더 나은 솔루션이 될 수 있습니다 예컨대 :

# !! NO output, because Sort-Object never finishes. 
1..5 | % { if ($_ -gt 2) { Stop-Pipeline }; $_ } | Sort-Object 

배경 정보 :

감사를 PetSerAl에 내 answer hereSelect-Object -First 상류 cmdlet을 중지하기 위해 내부적으로 사용하는 것과 같은 예외를 생성하는 방법을 보여줍니다.

그러나, 예외가 여기 그렇지 인 정지 배관 접속 자체라는 cmdlet을 내측으로부터이 발생되어, 상기 실시 예에서 사용 된

Stop-Pipeline아니다이 중지되어야하는 파이프 라인에 연결되어 있어야합니다 (포함 된 ForEach-Object (%) 블록 만 해당). 따라서 질문은 다음과 같습니다. 대상 파이프 라인의 컨텍스트에서 예외가 어떻게 throw 될 수 있습니까?

+0

비공개 멤버를 사용하여이를 수행하는 방법에 대한 내 대답을 참조하십시오. –

1

비공개 멤버를 기꺼이 사용하려는 경우 여기에서 파이프 라인을 중지하는 방법이 있습니다. 그것은 select-object이하는 것을 모방합니다. invoke-method (별칭 im)은 비공개 메소드를 호출하는 함수입니다. select-property (별칭 selp)은 비공개 속성을 선택하는 기능입니다. 그러나 일치하는 속성이 하나만있는 경우 자동으로 -ExpandProperty처럼 작동합니다. (직장에서 select-propertyinvoke-method을 작성 했으므로 해당 소스 코드를 공유 할 수 없습니다.)

# Get the system.management.automation assembly 
$script:smaa=[appdomain]::currentdomain.getassemblies()| 
     ? location -like "*system.management.automation*" 
# Get the StopUpstreamCommandsException class 
$script:upcet=$smaa.gettypes()| ? name -like "*StopUpstreamCommandsException *" 

function stop-pipeline { 
    # Create a StopUpstreamCommandsException 
    $upce = [activator]::CreateInstance($upcet,@($pscmdlet)) 

    $PipelineProcessor=$pscmdlet.CommandRuntime|select-property PipelineProcessor 
    $commands = $PipelineProcessor|select-property commands 
    $commandProcessor= $commands[0] 

    $ci = $commandProcessor|select-property commandinfo 
    $upce.RequestingCommandProcessor | im set_commandinfo @($ci) 

    $cr = $commandProcessor|select-property commandruntime 
    $upce.RequestingCommandProcessor| im set_commandruntime @($cr) 

    $null = $PipelineProcessor| 
     invoke-method recordfailure @($upce, $commandProcessor.command) 

    if ($commands.count -gt 1) { 
     $doCompletes = @() 
     1..($commands.count-1) | % { 
     write-debug "Stop-pipeline: added DoComplete for $($commands[$_])" 
     $doCompletes += $commands[$_] | invoke-method DoComplete -returnClosure 
     } 
     foreach ($DoComplete in $doCompletes) { 
     $null = & $DoComplete 
     } 
    } 

    throw $upce 
} 

편집 : mklement0의 의견에 따라 :

여기

유사 비공개 멤버에 대한 액세스를 제공하는 "찔러"모듈에서 스크립트에 Nivot 잉크 블로그에 link입니다.

추가 의견으로는이 시점에서 의미있는 의견이 없습니다. 이 코드는 select-object의 디 컴파일이 보여주는 것을 모방 한 것입니다. 원래의 MS 주석 (있는 경우)은 물론 디 컴파일되지 않습니다. 솔직하게 나는 함수가 사용하는 다양한 유형의 목적을 모른다. 그 수준의 이해를 얻으려면 상당한 노력이 필요할 것입니다.

나의 제안 : Oisin의 poke 모듈을 얻으십시오. 해당 모듈을 사용하도록 코드를 조정하십시오. 그리고 그것을 밖으로 시도하십시오. 작동 방식이 마음에 들면 사용하고 작동 방식에 대해 걱정하지 마십시오.

참고 : 어떤 깊이에서도 "멍청이"는 공부하지 않았지만 -returnClosure과 같은 것은 없다고 생각합니다. 그러나 그이 쉽게해야 추가 : - : 사실 :

if (-not $returnClosure) { 
    $methodInfo.Invoke($arguments) 
} else { 
    {$methodInfo.Invoke($arguments)}.GetNewClosure() 
} 
+0

인상적이지만 마음이 구부러진. 만약 당신이 그것을 가지고 있다면 아마도 더 많은 코멘트를 추가 할 수 있고 다른 사람들이'select-property'와'invoke-method'의 자신의 버전을 구현할 수있는 방법을 지적 할 것입니다. – mklement0

관련 문제