Я написал простой фильтр PowerShell, который толкает текущий объект по конвейеру, если его дата находится между указанной датой начала и окончания. Объекты, идущие вниз по конвейеру, всегда находятся в порядке возрастания даты, так как, как только дата превышает указанную дату окончания, я знаю, что моя работа выполнена, и я хотел бы сообщить конвейеру, что восходящие команды могут отказаться от своей работы, чтобы конвейер может завершить свою работу. Я читаю очень большие файлы журналов, и я часто захочу изучить только часть журнала. Я уверен, что это невозможно, но я хотел спросить, чтобы быть уверенным.Можно ли завершить или остановить конвейер PowerShell из фильтра
ответ
Невозможно остановить восходящую команду от нисходящей команды .. она будет продолжать отфильтровывать объекты, которые не соответствуют вашим критериям, но первая команда будет обрабатывать все, что было установлено для обработки.
Обходное решение будет состоять в том, чтобы больше фильтровать командлет вверх или функцию/фильтр. Работа с файлами журналов делает его более сложным, но, возможно, использование Select-String и регулярное выражение для фильтрации нежелательных дат может сработать для вас.
Если вы не знаете, сколько строк вы хотите взять и откуда, весь файл будет считаться для проверки шаблона.
Попробуйте эти фильтры, они заставят конвейер остановиться после первого объекта или первых n элементов и сохраните его -them- в переменной; вам нужно передать имя переменной, если вы не удаляете объект (ы), но не можете назначаться переменной.
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
Не уверен, что о ваших конкретных нужд, но это может быть стоит вашего времени, чтобы посмотреть на Log Parser, чтобы увидеть, если вы не можете использовать запрос для фильтрации данных, прежде чем он даже попадает в трубу.
Другим вариантом является использование параметра -file
в операторе switch
. Используя -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" }
}
Вы можете выбросить исключение при завершении трубопровода.
gc demo.txt -ReadCount 1 | %{$num=0}{$num++; if($num -eq 5){throw "terminated pipeline!"}else{write-host $_}}
или
Посмотрите на это сообщение о том, как прекратить трубопровод:
http://powershell.com/cs/blogs/tobias/archive/2010/01/01/cancelling-a-pipeline.aspx
можно сломать трубопровод с чем-нибудь, что бы в противном случае разорвать внешний контур или выполнение скрипта HALT (например, исключение). Тогда решение состоит в том, чтобы обернуть конвейер в цикл, который вы можете сломать, если вам нужно остановить конвейер.Например, следующий код возвращает первый элемент из трубопровода, а затем разорвать трубу, нарушая цикл снаружи делать-то время как:
do {
Get-ChildItem|% { $_;break }
} while ($false)
Эта функциональность может быть свернута в функцию, как это, где последняя строка выполняет то же самое, что и выше:
function Breakable-Pipeline([ScriptBlock]$ScriptBlock) {
do {
. $ScriptBlock
} while ($false)
}
Breakable-Pipeline { Get-ChildItem|% { $_;break } }
Вот - несовершенна - реализация Stop-Pipeline
командлета (требуется PS v3 +), с благодарностью адаптировано из this answer:
#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
Caveat: Я не совсем понимаю, как это работает, хотя в основном он использует способность преждевременного прекращения работы трубопровода (PS v3 +) Select -First
. Однако, в этом случае есть одна принципиальная разница в том, как Select -First
завершает трубопровод: вниз по течению командлетов (команды позже в трубопроводе) не получают шанс запустить свои end
блок.
Поэтому, агрегирование командлеты (те, которые должны получить все ввода, прежде чем производить выход, например, Sort-Object
Group-Object
и Measure-Object
) не будет производить выходной сигнал, если их поместить в тот же трубопровод; например .:
# !! NO output, because Sort-Object never finishes.
1..5 | % { if ($_ -gt 2) { Stop-Pipeline }; $_ } | Sort-Object
Справочная информация, которая может привести к лучшему решению:
Благодаря PetSerAl, мой answer here показывает, как производить то же самое исключение, которое Select-Object -First
использует внутренне, чтобы остановить вверх по течению командлеты.
Однако есть исключение брошено внутри командлета, который сам подключен к трубопроводу, чтобы остановить, что это не так здесь:
Stop-Pipeline
, как и в приведенных выше примерах, является не, подключенный к конвейеру, который должен быть остановлен (только блок ForEach-Object
(%
)), поэтому возникает вопрос: как можно исключить исключение в контексте целевого конвейера?
См. Мой ответ, чтобы сделать это, используя непубличных участников. – 2016-02-19 18:27:10
Если вы хотите использовать непубличных участников, это способ остановить конвейер. Он имитирует то, что делает select-object
. invoke-method
(псевдоним im
) является функцией вызова непубличных методов. select-property
(псевдоним selp
) - функция для выбора (аналогично select-object) негосударственных свойств - однако она автоматически действует как -ExpandProperty
, если найдено только одно свойство соответствия. (Я написал select-property
и invoke-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
}
EDIT: за комментарий mklement0 в:
Вот link для чернил блог Nivot на сценарии на «тыкать» модуль, который так же дает доступ к непубличным членам.
Что касается дополнительных комментариев, на данный момент у меня нет значимых. Этот код просто имитирует то, что раскрывает декомпиляция select-object
. Оригинальные комментарии MS (если они есть), конечно, не в декомпиляции. Честно говоря, я не знаю цели различных типов, которые использует функция. Получение такого уровня понимания, вероятно, потребует значительных усилий.
Мое предложение: получить модуль выталкивания Oisin. Измените код для использования этого модуля. И затем попробуйте. Если вам нравится, как это работает, используйте его и не беспокойтесь, как это работает (вот что я сделал).
Примечание: Я не изучал «выталкивание» на любой глубине, но я предполагаю, что у него ничего нет -returnClosure
. Однако, добавив, что должно быть легко, как это:
if (-not $returnClosure) {
$methodInfo.Invoke($arguments)
} else {
{$methodInfo.Invoke($arguments)}.GetNewClosure()
}
Это не работает в цикле - перерыв, кажется, остановить цикл тоже – 2009-11-15 01:05:23
@DavidGardiner: На самом деле: `` break` и continue` _не_ предназначены для выхода трубопроводы, они выходят из ветвей _loops_ (и `switch`). Если нет замкнутого цикла, то единственное, что происходит, это то, что функция завершена - что, поскольку побочный эффект завершает конвейер. Однако, если существует замкнутый цикл, тогда `break` и` continue` действуют соответственно, что может быть неожиданным. Простым, но хрупким и неудобным обходным путем является обертывание вызова в фиктивный цикл, как в ответе [@ MaximumCookie] (http://stackoverflow.com/a/30943992/45375). – mklement0 2016-01-16 22:23:00