我可以确定PowerShell功能是否作为管道的一部分运行?

时间:2010-12-28 21:48:03

标签: powershell powershell-v2.0

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 个答案:

答案 0 :(得分:17)

此信息作为$ PSCmdlet.MyInvocation的一部分提供。这是一个cmdlet,您可以使用它来试验这个。如果为任何命令执行写出该属性的内容一次然后传递对象(这样你就可以用更大的管道来操纵对象)它是做什么的。您将看到的是,有一个名为PipelineLength的属性,当您自行运行此命令时,该属性等于1,并且管道中的每个项目都会增加。另请注意PipelinePosition。它告诉你这个命令在管道中的位置。

注意: $PSCmdlet仅在您编写高级功能时可用(例如,具有[CmdletBinding()]属性。

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

答案 1 :(得分:6)

执行此操作的“惯用”方法是输出特定对象类型,然后为该对象定义格式数据。该对象可以是自定义(基于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

以下是我命名为MyCustomFormatData.xml的.ps1xml文件中定义的自定义格式定义:

<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