Могу ли я определить, работает ли функция PowerShell как часть конвейера? - PullRequest
14 голосов
/ 29 декабря 2010

Может ли функция PowerShell определить, выполняется ли она как часть конвейера? У меня есть функция, которая заполняет массив экземплярами FileInfo, которые я хотел бы «уступить» конвейеру, если функция выполняется таким образом, или выдать какой-нибудь симпатичный вывод, если функция вызывается сама из командной строки .

function Do-Something {
    $file_infos = @()
    # Populate $file_infos with FileInfo instances...

    if (INVOKED_IN_PIPELINE) {
        return $file_infos
    }
    else {
        foreach ($file_info in $file_infos) {
            write-host -foregroundcolor yellow $file_info.fullname
        }
    }
}

По сути, я пытаюсь понять, как реализовать INVOKED_IN_PIPELINE. Если он запускается в конвейере (например, Do-Something | format-table fullname), я бы просто вывел массив, но если запустить напрямую (например, Do-Something), он бы просто распечатал содержимое массива на консоль.

Есть ли способ сделать это? Если есть более «идиоматический» способ достижения такого рода вещей, мне также было бы интересно узнать.

Ответы [ 2 ]

18 голосов
/ 29 декабря 2010

Эта информация доступна как часть $ PSCmdlet.MyInvocation.Вот командлет, который вы можете использовать, чтобы поэкспериментировать с этим.Что он делает, чтобы выписать содержимое этого свойства один раз для выполнения любой команды, а затем передать объект (так что вы можете еще больше манипулировать объектами с помощью более крупных конвейеров).Вы увидите, что есть свойство с именем PipelineLength, которое равно 1, когда вы запускаете эту команду отдельно, и увеличивается для каждого элемента в конвейере.Также обратите внимание PipelinePosition.Она сообщает вам, какая позиция этой команды находится в конвейере.

ПРИМЕЧАНИЕ: $PSCmdlet доступна только при написании расширенной функции (например, иметь [CmdletBinding()] attribute.

function test-PSCmdlet
{
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true)]
$test
)
Begin{
    $once = $false
    }
process
    {
        if (!$once)
        {
            write-host ($PSCmdlet.MyInvocation |out-string)
            $once = $true
        }
        Write-Output $_
    }
}

Вот несколько примеров:

PS C:\Users\jsnover.NTDEV> test-PSCmdlet

MyCommand        : test-PSCmdlet
BoundParameters  : {}
UnboundArguments : {}
ScriptLineNumber : 1
OffsetInLine     : 14
HistoryId        : 61
ScriptName       : 
Line             : test-PSCmdlet
PositionMessage  : 
                   At line:1 char:14
                   + test-PSCmdlet <<<< 
InvocationName   : test-PSCmdlet
PipelineLength   : 1
PipelinePosition : 1
ExpectingInput   : False
CommandOrigin    : Runspace


PS C:\Users\jsnover.NTDEV> gps lsass | test-PSCmdlet |Format-table Name,Id -auto

MyCommand        : test-PSCmdlet
BoundParameters  : {[test, System.Diagnostics.Process (lsass)]}
UnboundArguments : {}
ScriptLineNumber : 1
OffsetInLine     : 26
HistoryId        : 62
ScriptName       : 
Line             : gps lsass | test-PSCmdlet |Format-table Name,Id -auto
PositionMessage  : 
                   At line:1 char:26
                   + gps lsass | test-PSCmdlet <<<<  |Format-table Name,Id -aut
                   o
InvocationName   : test-PSCmdlet
PipelineLength   : 3
PipelinePosition : 2
ExpectingInput   : True
CommandOrigin    : Runspace


Name   Id
----   --
lsass 620
7 голосов
/ 29 декабря 2010

«Идиоматический» способ сделать это - вывести определенный тип объекта и затем определить данные форматирования для этого объекта.Объект может быть пользовательским (объект на основе C # / VB) или именованным объектом PSObject.Преимущество этого подхода заключается в том, что вы можете просто выводить эти объекты, и если нет дальнейшего конвейерного форматирования вывода (т.е. использования команды Format), тогда вы определили форматирование вывода по умолчанию, которое будет использоваться.В противном случае одна из команд Format может переопределить форматирование по умолчанию.Вот пример:

PS> $obj = new-object psobject -Property @{FName = 'John'; LName = 'Doe'; `
                                           BirthDate = [DateTime]"5/7/1965"}
PS> $obj.psobject.TypeNames.Insert(0, "MyNamespace.MyCustomTypeName")
PS> $obj

BirthDate                               FName                            LName
---------                               -----                            -----
5/7/1965 12:00:00 AM                    John                             Doe


PS> Update-FormatData .\MyCustomFormatData.ps1xml
PS> $obj

FName                     LName                     BirthDate
-----                     -----                     ---------
John                      Doe                       5/7/1965 12:00:00 AM

Обратите внимание, как вывод по умолчанию отличается во второй раз, когда мы послали $obj по трубе.Это потому, что он использовал пользовательские инструкции по форматированию, так как не было никаких явных команд форматирования.

Кстати, всегда существует конвейер даже для $obj, потому что он неявно передается Out-Default.

Вот определение пользовательского формата, определенное в файле .ps1xml, который я назвал MyCustomFormatData.xml:

<Configuration>
  <ViewDefinitions>
    <View>
      <Name>MyNamespace.MyCustomTypeName</Name>
      <ViewSelectedBy>
        <TypeName>MyNamespace.MyCustomTypeName</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <TableHeaders>
          <TableColumnHeader>
            <Label>FName</Label>
            <Width>25</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>LName</Label>
            <Width>25</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>BirthDate</Label>
            <Width>25</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>FName</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>LName</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>BirthDate</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>

Дополнительные примеры форматирования пользовательских объектов см. В файлах.вывод этой команды:

Get-ChildItem $pshome\*.format.ps1xml
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...