如何直接通过管道传输到 Copy-Item 而不是在 ForEach-Object 内

Bar*_*tel 2 powershell pipeline copy-item foreach-object

由于使用 -Recurse 标志时,Get-ChildItem 的 -Exclude 参数不会对子文件夹进行过滤,因此请参阅使用 get-childitem-exclude-parameter-in-powershell 中的其他无法排除目录的内容

但 -Exclude 参数可用于过滤掉根级别的文件夹

我写了自己的递归函数:

function Get-ChildItem-Recurse() {
    [cmdletbinding()]
    Param(
      [parameter(ValueFromPipelineByPropertyName = $true)]
      [alias('FullName')]
      [string[]] $Path,
      [string] $Filter,
      [string[]] $Exclude,
      [string[]] $Include,
      [switch] $Recurse = $true,
      [switch] $File = $false
    )

    Process {
      ForEach ( $P in $Path ) {
        Get-ChildItem -Path $P -Filter $Filter -Include $Include -Exclude $Exclude | ForEach-Object {
        if ( -not ( $File -and $_.PSIsContainer ) ) {
          $_
        }
        if ( $Recurse -and $_.PSIsContainer ) {
          $_ | Get-ChildItem-Recurse -Filter $Filter -Exclude $Exclude -Include $Include -Recurse:$Recurse
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

当我将结果通过管道传输到 ForEach-Object 以将结果复制到不同的目标时,一切正常,并且复制除与排除参数匹配的项目之外的项目

$source = 'D:\Temp\'
$destination = 'D:\Temp_Copy\'

Get-ChildItem-Recurse -Path $source -Exclude @( '*NotThis*', '*NotThat*' ) | ForEach-Object {
  $_ | Copy-Item -Destination ( "$($destination)$($_.FullName.Substring($source.Length))" ) -Force 
}
Run Code Online (Sandbox Code Playgroud)

当我将其直接通过管道传输到 Copy-Item commandlet 时,我收到一个空值错误,因为在 $_.FullName 上调用了 .Substring() ,而 $_.FullName 显然为 null

Get-ChildItem-Recurse -Path $source -Exclude @( '*NotThis*', '*NotThat*' ) |
  Copy-Item -Destination ( "$($destination)$($_.FullName.Substring($source.Length))" ) -Force
Run Code Online (Sandbox Code Playgroud)

因为本机命令行开关 Get-ChildItem 确实允许我将其结果通过管道传输到 Copy-Item,所以我喜欢我自己的自定义函数也能够做到这一点。但我不明白为什么它不起作用。

Mat*_*sen 6

使用脚本块将管道输入值动态绑定到参数:

Get-ChildItem ... |Copy-Item -Destination { "$($destination)$($_.FullName.Substring($source.Length))" }
Run Code Online (Sandbox Code Playgroud)

mklement0 的以下答案提供了有关这种动态绑定的详细信息(追溯性地命名为“delay-bind scriptblocks”,或通俗地称为“pipeline-bound scriptblocks”):
对于 PowerShell cmdlet,我可以始终将脚本块传递给字符串参数吗?

  • @CFou它适用于设置了“ValueFromPipeline”的任何参数:) (2认同)