【问题标题】:How to pipe directly to Copy-Item instead of within a ForEach-Object如何直接通过管道传输到 Copy-Item 而不是在 ForEach-Object 内
【发布时间】:2021-12-08 12:47:24
【问题描述】:

因为 Get-ChildItem 的 -Exclude 参数在使用 -Recurse 标志时未过滤子文件夹,请参阅unable-to-exclude-directory-using-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
        }
      }
    }
  }
}

当我将结果通过管道传输到 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 
}

当我将它直接通过管道传输到 Copy-Item 命令行开关时,我收到一个空值错误,因为在 $_.FullName 上调用了显然为空的 .Substring()

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

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

【问题讨论】:

    标签: powershell pipeline copy-item foreach-object


    【解决方案1】:

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

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

    mklement0 的以下回答详细介绍了这种动态绑定(追溯命名为 "delay-bind scriptblocks",或通俗地称为“管道绑定脚本块”):
    For PowerShell cmdlets, can I always pass a script block to a string parameter?

    【讨论】:

    • 此方法适用于其他几个 cmdlet,例如 Rename-Item 。如果可用,我总是更喜欢这种方式而不是ForEach-Object
    • @CFou 它适用于设置ValueFromPipeline的任何参数:)
    • 很高兴知道ValueFromPipeline 属性!不知道这个。
    • 感谢马蒂亚斯的更新。毫无疑问:该功能适用​​于 ValueFromPipelineValueFromPipelineByPropertyName 参数(有时单个参数同时适用)。例如,要发现给定 cmdlet 的管道绑定参数,请使用 Get-Help Copy-Item -Parameter * | Where pipelineInput -like True* - 有关详细信息,请参阅 this answer。 /cc @AbrahamZinala。
    【解决方案2】:

    通常你通过管道复制源代码:

    $source = 'D:\Temp\'
    $destination = 'D:\Temp_Copy\'
    
    get-childitem $source | copy-item -destination $destination -whatif
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 2014-12-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-27
      • 2016-06-14
      相关资源
      最近更新 更多