powershell 如何一次获取所有管道元素?

64jmpszr  于 2023-03-12  发布在  Shell
关注(0)|答案(1)|浏览(90)

我创建了这个非常简单的PowerShell脚本:

using namespace System.IO

[CmdletBinding(SupportsShouldProcess)]
param
(
  [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)][FileInfo[]]$Files
)
$Files.Length
$Files | Sort-Object | ForEach-Object {$_.Name}

当我用Get-ChildItem调用的任何结果调用它时,$Files.Length总是1,不管目录中有多少文件:

PS C:\Temp> Get-ChildItem -File C:\Windows\ | .\Rename-Test.ps1
1
WMSysPr9.prx

我做错了什么?

yr9zkbsy

yr9zkbsy1#

基本上你的脚本只缺少一个process块,否则,默认块是end,这样你就只能看到来自管道的最后一个元素。

using namespace System.IO

[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
param
(
    [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
    [FileInfo[]] $Files
)

process {
    foreach($file in $Files) {
        if($PSCmdlet.ShouldProcess($file.Name, 'Doing something')) {
            $file.FullName
        }
    }
}

正如您可能注意到的,由于-Files参数的类型为[FileInfo[]]FileInfo示例数组),因此在通过命名参数或按位置传递参数的情况下需要循环。
但是,如果您需要收集所有输入,即对其进行排序,则需要List<T>来收集process块中的每个对象,然后在end块中处理收集的输入,例如:

using namespace System.IO

[CmdletBinding()]
param
(
    [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
    [FileInfo[]] $Files
)

begin {
    $items = [System.Collections.Generic.List[FileInfo]]::new()
}
process {
    $items.AddRange($Files)
}
end {
    $items | Sort-Object Length
}

那么对于上述情况,两种方法都可以很好地工作:

# from pipeline
Get-ChildItem -File | .\myscript.ps1

# from positional binding
.\myscript.ps1 (Get-ChildItem -File)

相关问题