views:

427

answers:

4

I have written a simple PowerShell filter that pushes the current object down the pipeline if its date is between the specified begin and end date. The objects coming down the pipeline are always in ascending date order so as soon as the date exceeds the specified end date I know my work is done and I would like to let tell the pipeline that the upstream commands can abandon their work so that the pipeline can finish its work. I am reading some very large log files and I will frequently want to examine just a portion of the log. I am pretty sure this is not possible but I wanted to ask to be sure.

+1  A: 

It is not possible to stop an upstream command from a downstream command.. it will continue to filter out objects that do not match your criteria, but the first command will process everything it was set to process.

The workaround will be to do more filtering on the upstream cmdlet or function/filter. Working with log files makes it a bit more comoplicated, but perhaps using Select-String and a regular expression to filter out the undesired dates might work for you.

Unless you know how many lines you want to take and from where, the whole file will be read to check for the pattern.

Steven Murawski
+1  A: 

Try these filters, they'll force the pipeline to stop after the first object -or the first n elements- and store it -them- in a variable; you need to pass the name of the variable, if you don't the object(s) are pushed out but cannot be assigned to a variable.

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
This doesn't work in a loop - the break seems to stop the loop too
David Gardiner
+1  A: 

Not sure about your exact needs, but it may be worth your time to look at Log Parser to see if you can't use a query to filter the data before it even hits the pipe.

EBGreen
A: 

Another option would be to use the -file parameter on a switch statement. Using -file will read the file one line at a time, and you can use break to exit immediately without reading the rest of the file.

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