2012-02-17 2 views
11

У меня есть команда Get-Testdata, которая извлекает тестовые данные из разных источников и сохраняет их в PSObject с различными значениями в качестве свойств. Общее количество объектов затем хранится в виде массива, для удобства манипуляции, сортировки, вычисления и т. Д.Поведение ValueFromPipeline?

Проблема заключается в том, что я хочу, чтобы иметь возможность представить эти данные как (цветные) HTML, ve написала другую команду, Show-TestResults. Входной параметр выглядит следующим образом

[Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true)] 
[PSObject[]]$InputObject 

UPDATE 1

сама эта функция очень проста, она просто устанавливает некоторые параметры для ConvertTo-HTML а затем передать объекты в эту команду:

$head = "<style>[...]" #styling with javascript etc 
$header = "<H1>Test Results</H1> 
$title = "Test results" 
$InputObject | ConvertTo-HTML -head $head -body $header -title $title | Out-File $Filename 

END UPDATE 1

H owever, когда я пытаюсь использовать ValueFromPipeline свойство, с помощью вызова

Get-Testdata [...] | Show-TestResults 

только первый объект в массиве показано. Но если я вместо этого назову команду, как

$td = Get-Testdata [...] 
Show-TestResults $td 

Весь массив представлен, как и ожидалось. Может кто-то объяснить это - и, надеюсь, поможет мне исправить это?

+0

Вы хотите, чтобы показать, как ваша функция выглядит как (примерно), и как вы используете $ InputObject там? Если там будет ошибка, мы это увидим. –

+0

Обновлено теперь с помощью функций –

ответ

9

Вероятно, вы обрабатываете данные в конечном блоке, а не в блоке процесса.

Посмотрите на пример:

function getdata { 
    1 
    2 
    3 
    4 
} 
function show-data { 
    param(
     [Parameter(mandatory=$true, ValueFromPipeline=$true)]$InputObject, 
     [Parameter(mandatory=$true)]$FileName 
    ) 

    # this is process block that is probably missing in your code 
    begin { $objects = @() } 
    process { $objects += $InputObject } 
    end { 
     $head = "<style></style>" 
     $header = "<H1>Test Results</H1>" 
     $title = "Test results" 
     $objects | ConvertTo-HTML -head $head -body $header -title $title | Out-File $Filename 
    } 
} 

getdata | show-data -file d:\temp\test.html 
+0

Спасибо, но, как вы можете видеть из моего вышеприведенного обновления, размещение HTML-преобразования в блок 'process' просто делает только последнее сообщение« пройти » –

+0

Обновлено. Вам нужно собрать объекты и передать их в концевый блок. Другой метод, вероятно, будет использовать прокси-функции, но это намного проще. – stej

+0

Спасибо, собирая вход в другой массив во время 'process {}' сделал трюк. Но мне все же интересно узнать, почему поведение отличается в зависимости от того, как параметр получает свои данные, для меня они должны вести себя одинаково. –

2

Я думаю, что проблема в том, что трубопровод разворачивая ваш массив в поток объектов и представление их в свою функцию по одному, а не как массив ,

ли работа, если вы сделаете это:

,(Get-Testdata [...]) | Show-TestResults 
4

Если продвинутая функция является требование, то я пошел бы в пути, предложенному @stej.

В противном случае я хотел бы рассмотреть эту простую технику, когда функция принимает и трубопровода и параметров ввода:

function Show-Data 
(
    $FileName, 
    $InputObject 
) 
{ 
    # this is the trick: 
    if ($InputObject) { $input = $InputObject } 

    # process the input (from pipeline or parameter) 
    $input | ConvertTo-HTML > $FileName 
} 

# pipe data 
Get-ChildItem | Show-Data Test1.htm 

# pass via parameter 
Show-Data Test2.htm (Get-ChildItem) 

нотабене $input в этом случае является автоматической переменной для ввода конвейера.

+0

Это работает также (я уже пробовал с помощью '$ input'), но поскольку я хочу контролировать параметр, ответ @ stej выше подходит мне лучше. –

1

я наткнулся на тот же вопрос/вопрос и так, как я обычно решить эту проблему, как:

Function Show-Data { 
    param(
     [Parameter(mandatory=$true, ValueFromPipeline=$true)]$InputObject, 
     [Parameter(mandatory=$true)]$FileName 
    ) 
    $PipeLine = $Input | ForEach {$_}; If ($PipeLine) {$InputObject = $PipeLine} 
    ... 

Как я не думаю, что это хорошая идея, чтобы перезаписатьautomatic $Input variable.

Во всяком случае, я не видел ответа на часть вопроса: «Может кто-нибудь объяснить это? "
Я думаю, что это имеет какое-то отношение к Strongly Encouraged Development Guidelines, которая гласит:

Поддержки ProcessRecord Метод
Чтобы принять все записи из предыдущего командлета в трубопроводе, вашей команда должна реализовать ProcessRecord метод. Окна PowerShell вызывает этот метод несколько раз, один раз для каждой записи , который отправляется на ваш командлет.

метод ProcessRecord появляется s мне как метод C#, который, как я полагаю, вызывается блоком process, как в решении от stej. Но это не объясняет, почему это работает таким образом для массива PSCustomObject, а не для, например, системные объекты, такие как:

Get-psdrive | Show-Data 

Или даже:

@(Get-psdrive) | Show-Data 
Смежные вопросы