2015-11-04 4 views
2

Есть пару хороших ответы о проходящих функцияхPass Cmdlet в качестве параметра Функции

function pass_function([scriptblock] $func, [int] $a){ 
    func.invoke($a) 
} 

Как бы вы пройти командлеты, которые принимают водопроводный ввод? У меня плохое решение

function pass_through([scriptblock]$command){ 
    $command.invoke() 
} 

1,2,3,4 | pass_through { $input | Where { $_ -gt 1} } 

выходы 2, 3, 4.

Технически Есть достаточное количество инструментов, но они требуют пустячный реализации. Я бы предпочел передать Where и {$ _ -gt 1} в качестве отдельных параметров.

Если у вас нет хорошей поддержки, то какой стиль этого языка для решения подобных проблем?

+2

Вы можете уточнить, почему вы делаете это таким образом? Мета-программирование - это весело и все, но мне любопытно. Почему вы не можете сделать выделенную функцию, которая принимает эти параметры, которые вы хотите ... обрабатывать и продолжать с конвейером. – Matt

+0

Пример был выбран для простоты. Но предположим, что у меня есть инструмент «logging», который проверяет влияние CmdLet на вход в канале.Таким образом, у нас может быть «input | remember | selectedCmdLet | difference» Где «запомнить» может каким-то образом пометить значения, а «разница» сигнализируется, когда элемент в потоке был удален или изменен. Было бы неплохо, если бы я мог просто вызвать Test selectedCmdLet вместо вызова между этими двумя командлетами. – Polymer

+1

Функция @Polymer 'Test {param ([ScriptBlock] $ Command) input | запомнить | Invoke-Command $ Command | difference}' 'Test {Where {$ _ -gt 1}}' – PetSerAl

ответ

2

Похоже, вы ищете способ изменить команду в середине конвейера без написания другой копии конвейера. Вы можете добиться этого, вызвав ScriptBlock как SteppablePipeline. Приятно то, что Invoke-Command Командлет может сделать это для вас, если все следующие условия встречаются:

  • Invoke-Command ожидают ввода трубопровода.
  • ScriptBlock не имеет прямой ссылки на $input.
  • ScriptBlock конвертируемый в SteppablePipeline.

Вот Pass_Through функция:

function Pass_Through { 
    param(
     [ScriptBlock]$MiddleCommand 
    ) 
    $input| 
    Pre-Command| 
    Invoke-Command $MiddleCommand| 
    Post-Command 
} 

И вы можете вызвать его так:

1..10|Pass_Through {Where { $_ -gt 1}} 
2

Таким образом, проблема в том, что разные командлеты будут иметь разные способы их вызова. Например, передача 1,2,3,4 в предложение Where в порядке, ему нравятся массивы почти ничего, но вы не можете передать это Format-Table, потому что он просто не принимает массив строк, ему нужно массив объектов.

Для вашего Where цель вы могли бы сделать что-то вроде:

Function Pass_Through { 
Param(
    [string]$Cmd, 
    [string]$Arguments 
) 
Process{[scriptblock]::Create("`$input|$cmd $arguments").Invoke()} 
} 

Тогда, когда мы делаем:

1,2,3,4 | pass_through 'Where' '{ $_ -gt 1}' 

Он реагирует с 2, 3, 4, как и ожидалось. Но что происходит, когда вы хотите передать объект, а не строку?

Get-ADUser $env:USERNAME | Pass_Through 'Format-Table' 'Name,DistinguishedName' 

не произойдет, потому что он пытается экстраполировать каждое свойство и передать каждую строку в Format-Table командлета, и что просто не работает.

+0

Я проголосовал за это как правильно, так как он полностью решает общую проблему. Хотя, потому что я новичок в этом, я не уверен, как указать CmdLet из странного пространства имен. Не хотите ли вы, чтобы процесс закончился? И как бы вы лично решали эти проблемы? Потому что это немного заставляет. – Polymer

+1

Вы должны сбежать из '$ input' в блок сценария:' '' '$ input | $ cmd $ arguments'''. Попробуйте следующее: '' dir '| Pass_Through foreach' {$ _} ''. Он не печатает 'dir', а результат команды' dir'. – PetSerAl

+0

@PetSerAl Отличное предложение! Я внес изменения в свой ответ. – TheMadTechnician

Смежные вопросы