Can I determine if a PowerShell function is running as part of a pipeline?

前端 未结 2 1225
生来不讨喜
生来不讨喜 2021-02-07 10:52

Can a PowerShell function determine if it is being run as part of a pipeline? I have a function which populates an array with instances of FileInfo which I would li

相关标签:
2条回答
  • 2021-02-07 11:35

    This information is available as part of $PSCmdlet.MyInvocation. Here is a cmdlet you can use to experiment with this. What it does it to write out the contents of that property once for any command execution and then passes on the object (so you can manipulate the objects some more with bigger pipelines). What you'll see is that there is a property called PipelineLength which is equal to 1 when you run this command by itself and increases for each item in the pipeline. Also notice PipelinePosition. It tells you what position this command is in the pipeline.

    NOTE: $PSCmdlet is only available when you write an advanced function (e.g. have the [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 $_
        }
    }
    

    Here are some examples:

    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
    
    0 讨论(0)
  • 2021-02-07 11:40

    The "idiomatic" way to do this is to output a specific object type and then define formatting data for that object. The object can be a custom (C#/VB-based object) or a named PSObject. The advantage of this approach is that you can just output these objects and if there is no further pipeline output formatting (ie use of a Format command) then you're defined default output formatting will get used. Otherwise, one of the Format commands can override that default formatting. Here's an example:

    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
    

    Notice how the default output is different the second time we sent $obj down the pipe. That's because it used the custom formatting instructions provided since there were no explicit formatting commands used.

    BTW there is always a pipeline even for $obj because that is implicitly piped to Out-Default.

    Here is the custom format definition that is defined in a .ps1xml file that I named 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>
    

    For more examples of how to format custom objects look at the files output by this command:

    Get-ChildItem $pshome\*.format.ps1xml
    
    0 讨论(0)
提交回复
热议问题