如何编写接受管道输入的PowerShell脚本?

时间:2022-04-15 15:41:01

I am trying to write a PowerShell script that can get pipeline input (and is expected to do so), but trying something like

我正在尝试编写一个可以获取管道输入的PowerShell脚本(并且预计会这样做),但尝试类似的东西

ForEach-Object {
   # do something
}

doesn't actually work when using the script from the commandline as follows:

使用命令行中的脚本时实际上不起作用,如下所示:

1..20 | .\test.ps1

Is there a way?

有办法吗?

Note: I know about functions and filters. This is not what I am looking for.

注意:我了解功能和过滤器。这不是我要找的。

4 个解决方案

#1


38  

This works and there are probably other ways to do it:

这有效,可能有其他方法可以做到:

foreach ($i in $input) {
    $i
}

17:12:42 PS>1..20 | .\cmd-input.ps1
1
2
3
-- snip --
18
19
20

17:12:42 PS> 1..20 | 。\ cmd-input.ps1 1 2 3 - snip - 18 19 20

Search for "powershell $input variable" and you will find more information and examples.
A couple are here:
PowerShell Functions and Filters PowerShell Pro!
(see the section on "Using the PowerShell Special Variable “$input”")
"Scripts, functions, and script blocks all have access to the $input variable, which provides an enumerator over the elements in the incoming pipeline. "
or
$input gotchas « Dmitry’s PowerBlog PowerShell and beyond
"... basically $input in an enumerator which provides access to the pipeline you have."

搜索“powershell $输入变量”,您将找到更多信息和示例。一对夫妇在这里:PowerShell功能和过滤器PowerShell专业版! (请参阅“使用PowerShell特殊变量”部分$ input“”)“脚本,函数和脚本块都可以访问$ input变量,该变量为传入管道中的元素提供枚举器。”或$ input陷阱«德米特里的PowerBlog PowerShell及其他“...基本上是一个枚举器中的$输入,它提供了对你所拥有的管道的访问。”

For the PS command line, not the DOS command line Windows Command Processor.

对于PS命令行,不是DOS命令行Windows Command Processor。

#2


104  

In v2 you can also accept pipeline input (by propertyName or byValue), add parameter aliases etc:

在v2中,您还可以接受管道输入(通过propertyName或byValue),添加参数别名等:

function Get-File{
    param(  
    [Parameter(
        Position=0, 
        Mandatory=$true, 
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true)
    ]
    [Alias('FullName')]
    [String[]]$FilePath
    ) 

    process {
       foreach($path in $FilePath)
       {
           Write-Host "file path is: $path"
       }
    }
}


# test ValueFromPipelineByPropertyName 
dir | Get-File

# test ValueFromPipeline (byValue) 

"D:\scripts\s1.txt","D:\scripts\s2.txt" | Get-File

 - or -

dir *.txt | foreach {$_.fullname} | Get-File

#3


23  

You can either write a filter which is a special case of a function like so:

您可以编写一个过滤器,这是一个函数的特殊情况,如下所示:

filter SquareIt([int]$num) { $_ * $_ }

or you can create a similar function like so:

或者你可以像这样创建一个类似的函数:

function SquareIt([int]$num) {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

The above works as an interactive function definiton or if in a script can be dotted into your global session (or another script). However your example indicated you wanted a script so here it is in a script that is directly usable (no dotting required):

以上工作作为交互式函数定义,或者如果在脚本中可以分散到您的全局会话(或其他脚本)中。但是你的例子表明你想要一个脚本,所以这里它是一个可以直接使用的脚本(不需要打点):

  --- Contents of test.ps1 ---
  param([int]$num)

  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }

With PowerShell V2, this changes a bit with "advanced functions" which embue functions with the same parameter binding features that compiled cmdlets have. See this blog post for an example of the differences. Also note that in this advanced functions case you don't use $_ to access the pipeline object. With advanced functions, pipeline objects get bound to a parameter just like they do with a cmdlet.

使用PowerShell V2,这会改变一些“高级功能”,它使用与编译的cmdlet相同的参数绑定功能来实现功能。有关差异的示例,请参阅此博客文章。另请注意,在此高级函数的情况下,您不使用$ _来访问管道对象。使用高级函数,管道对象绑定到参数,就像使用cmdlet一样。

#4


7  

The following are the simplest possible examples of scripts/functions that use piped input. Each behaves the same as piping to the "echo" cmdlet.

以下是使用管道输入的脚本/函数的最简单示例。每个行为与管道到“echo”cmdlet的行为相同。

As Scripts:

作为脚本:

# Echo-Pipe.ps1
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
# Echo-Pipe2.ps1
foreach ($i in $input) {
    $i
}

As functions:

作为功​​能:

Function Echo-Pipe {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

Function Echo-Pipe2 {
    foreach ($i in $input) {
        $i
    }
}

E.g.

例如。

PS > . theFileThatContainsTheFunctions.ps1 # This includes the functions into your session
PS > echo "hello world" | Echo-Pipe
hello world
PS > cat aFileWithThreeTestLines.txt | Echo-Pipe2
The first test line
The second test line
The third test line

#1


38  

This works and there are probably other ways to do it:

这有效,可能有其他方法可以做到:

foreach ($i in $input) {
    $i
}

17:12:42 PS>1..20 | .\cmd-input.ps1
1
2
3
-- snip --
18
19
20

17:12:42 PS> 1..20 | 。\ cmd-input.ps1 1 2 3 - snip - 18 19 20

Search for "powershell $input variable" and you will find more information and examples.
A couple are here:
PowerShell Functions and Filters PowerShell Pro!
(see the section on "Using the PowerShell Special Variable “$input”")
"Scripts, functions, and script blocks all have access to the $input variable, which provides an enumerator over the elements in the incoming pipeline. "
or
$input gotchas « Dmitry’s PowerBlog PowerShell and beyond
"... basically $input in an enumerator which provides access to the pipeline you have."

搜索“powershell $输入变量”,您将找到更多信息和示例。一对夫妇在这里:PowerShell功能和过滤器PowerShell专业版! (请参阅“使用PowerShell特殊变量”部分$ input“”)“脚本,函数和脚本块都可以访问$ input变量,该变量为传入管道中的元素提供枚举器。”或$ input陷阱«德米特里的PowerBlog PowerShell及其他“...基本上是一个枚举器中的$输入,它提供了对你所拥有的管道的访问。”

For the PS command line, not the DOS command line Windows Command Processor.

对于PS命令行,不是DOS命令行Windows Command Processor。

#2


104  

In v2 you can also accept pipeline input (by propertyName or byValue), add parameter aliases etc:

在v2中,您还可以接受管道输入(通过propertyName或byValue),添加参数别名等:

function Get-File{
    param(  
    [Parameter(
        Position=0, 
        Mandatory=$true, 
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true)
    ]
    [Alias('FullName')]
    [String[]]$FilePath
    ) 

    process {
       foreach($path in $FilePath)
       {
           Write-Host "file path is: $path"
       }
    }
}


# test ValueFromPipelineByPropertyName 
dir | Get-File

# test ValueFromPipeline (byValue) 

"D:\scripts\s1.txt","D:\scripts\s2.txt" | Get-File

 - or -

dir *.txt | foreach {$_.fullname} | Get-File

#3


23  

You can either write a filter which is a special case of a function like so:

您可以编写一个过滤器,这是一个函数的特殊情况,如下所示:

filter SquareIt([int]$num) { $_ * $_ }

or you can create a similar function like so:

或者你可以像这样创建一个类似的函数:

function SquareIt([int]$num) {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

The above works as an interactive function definiton or if in a script can be dotted into your global session (or another script). However your example indicated you wanted a script so here it is in a script that is directly usable (no dotting required):

以上工作作为交互式函数定义,或者如果在脚本中可以分散到您的全局会话(或其他脚本)中。但是你的例子表明你想要一个脚本,所以这里它是一个可以直接使用的脚本(不需要打点):

  --- Contents of test.ps1 ---
  param([int]$num)

  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }

With PowerShell V2, this changes a bit with "advanced functions" which embue functions with the same parameter binding features that compiled cmdlets have. See this blog post for an example of the differences. Also note that in this advanced functions case you don't use $_ to access the pipeline object. With advanced functions, pipeline objects get bound to a parameter just like they do with a cmdlet.

使用PowerShell V2,这会改变一些“高级功能”,它使用与编译的cmdlet相同的参数绑定功能来实现功能。有关差异的示例,请参阅此博客文章。另请注意,在此高级函数的情况下,您不使用$ _来访问管道对象。使用高级函数,管道对象绑定到参数,就像使用cmdlet一样。

#4


7  

The following are the simplest possible examples of scripts/functions that use piped input. Each behaves the same as piping to the "echo" cmdlet.

以下是使用管道输入的脚本/函数的最简单示例。每个行为与管道到“echo”cmdlet的行为相同。

As Scripts:

作为脚本:

# Echo-Pipe.ps1
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
# Echo-Pipe2.ps1
foreach ($i in $input) {
    $i
}

As functions:

作为功​​能:

Function Echo-Pipe {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

Function Echo-Pipe2 {
    foreach ($i in $input) {
        $i
    }
}

E.g.

例如。

PS > . theFileThatContainsTheFunctions.ps1 # This includes the functions into your session
PS > echo "hello world" | Echo-Pipe
hello world
PS > cat aFileWithThreeTestLines.txt | Echo-Pipe2
The first test line
The second test line
The third test line