在PowerShell中排除列表Copy-Item似乎不工作

我有以下PowerShell脚本片段:

$source = 'd:\t1\*' $dest = 'd:\t2' $exclude = @('*.pdb','*.config') Copy-Item $source $dest -Recurse -Force -Exclude $exclude 

它可以将所有文件和文件夹从t1复制到t2,但是它只排除“root”/“first-level”文件夹中的排除列表,而不包含子文件夹中的排除列表。

如何使其排除所有文件夹中的排除列表?

我认为最好的方法是在Copy-Item命令中使用Get-ChildItem和pipe。

我发现这工作:

 $source = 'd:\t1' $dest = 'd:\t2' $exclude = @('*.pdb','*.config') Get-ChildItem $source -Recurse -Exclude $exclude | Copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)} 

基本上,这里发生的事情是,你正在逐一浏览有效的文件,然后将它们复制到新的path。 最后的“Join-Path”语句使得复制文件时还保留了目录。 该部分将目标目录与源path之后的目录结合在一起。

我从这里得到了这个想法,然后修改了一下,使它适用于这个例子。

我希望它的作品!

exclude参数不适用于dirs。 Bo的脚本的一个变种是诀窍:

 $source = 'c:\tmp\foo' $dest = 'c:\temp\foo' $exclude = '\.bak' Get-ChildItem $source -Recurse | where {$_.FullName -notmatch $exclude} | Copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)} 

由于评论格式代码糟糕,我会发布答案,但这只是@ landyman的答案的补充。 build议的脚本有一个缺点 – 它会创build双嵌套的文件夹。 例如,对于'd:\ t1 \ sub1',它将创build空目录'd:\ t2 \ sub1 \ sub1'。 这是由于目录的Copy-Item需要-Destination属性中的父目录名称而不是目录名称本身。 这是我find的解决方法:

  Get-ChildItem -Path $from -Recurse -Exclude $exclude | Copy-Item -Force -Destination { if ($_.GetType() -eq [System.IO.FileInfo]) { Join-Path $to $_.FullName.Substring($from.length) } else { Join-Path $to $_.Parent.FullName.Substring($from.length) } } 

我也遇到了这个问题,花了20分钟的时间在这里应用解决scheme,但一直有问题。
所以我select了使用robocopy – 确定,它不是powershell,但应该在PowerShell运行的任何地方都可用。

它开箱即用:

 robocopy $source $dest /S /XF <file patterns to exclude> /XD <directory patterns to exclude> 

例如

 robocopy $source $dest /S /XF *.csproj /XD obj Properties Controllers Models 

另外,它有很多function,如可恢复的副本。 文档在这里 。

我正在寻找一种方法来复制特定date/时间戳后修改的文件,以便将其归档。 通过这种方式,我可以节省什么文件我工作(假设我知道当我开始)。 (是的,我知道这是SCM的用途,但是有时我只想快照我的作品而不检查它。)

用landyman的小费,以及其他地方find的东西,我发现这个工作:

 $source = 'c:\tmp\foo' $dest = 'c:\temp\foo' $exclude = @('*.pdb', '*.config') Get-ChildItem $source -Recurse -Exclude $exclude | where-object {$_.lastwritetime -gt "8/24/2011 10:26 pm"} | Copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)} 

带有Join-Path的Get-ChildItem主要是为我工作的,但是我意识到它正在复制其他根目录内的根目录,这很糟糕。

例如

  • C:\ SomeFolder
  • C:\ SomeFolder \ CopyInHere
  • C:\ SomeFolder \ CopyInHere \ Thing.txt
  • C:\ SomeFolder \ CopyInHere \子文件夹
  • C:\ SomeFolder \ CopyInHere \子文件夹\ Thin2.txt

  • 源目录:c:\ SomeFolder \ CopyInHere

  • 目的地目录:d:\ PutItInHere

目标:复制每个子项内部c:\ SomeFolder \ CopyInHere到d:\ PutItInHere的根目录,但不包括c:\ SomeFolder \ CopyInHere本身。
– 例如带着CopyInHere的所有孩子,让他们成为PutItIneere的儿童

上面的例子大部分都是这样做的,但是它会创build一个名为SubFolder的文件夹,并在名为SubFolder的文件夹中创build一个文件夹。

这是因为Join-Path计算SubFolder子项的d:\ PutItInHere \ SubFolder的目标path,所以SubFolder get的创build在名为SubFolder的文件夹中。

我通过使用Get-ChildItems来回收这些项目的集合,然后使用一个循环来完成它。

 Param( [Parameter(Mandatory=$True,Position=1)][string]$sourceDirectory, [Parameter(Mandatory=$True,Position=2)][string]$destinationDirectory ) $sourceDI = [System.IO.DirectoryInfo]$sourceDirectory $destinationDI = [System.IO.DirectoryInfo]$destinationDirectory $itemsToCopy = Get-ChildItem $sourceDirectory -Recurse -Exclude @('*.cs', 'Views\Mimicry\*') foreach ($item in $itemsToCopy){ $subPath = $item.FullName.Substring($sourceDI.FullName.Length) $destination = Join-Path $destinationDirectory $subPath if ($item -is [System.IO.DirectoryInfo]){ $itemDI = [System.IO.DirectoryInfo]$item if ($itemDI.Parent.FullName.TrimEnd("\") -eq $sourceDI.FullName.TrimEnd("\")){ $destination = $destinationDI.FullName } } $itemOutput = New-Object PSObject $itemOutput | Add-Member -Type NoteProperty -Name Source -Value $item.FullName $itemOutput | Add-Member -Type NoteProperty -Name Destination -Value $destination $itemOutput | Format-List Copy-Item -Path $item.FullName -Destination $destination -Force } 

简而言之,它使用当前项目的全名作为目的地计算。 然而,它然后检查,看看它是否是一个DirectoryInfo对象。 如果是,则检查父文件夹是否为源目录,这意味着当前正在迭代的文件夹是源目录的直接子目录,因此我们不应将其名称附加到目标目录,因为我们希望该文件夹是在目标目录中创build,而不是在目标目录中的文件夹中创build。

之后,其他文件夹将正常工作。

 $sourcePath="I:\MSSQL\Backup\Full" $excludedFiles=@("MASTER", "DBA", "MODEL", "MSDB") $sourceFiles=(ls $sourcePath -recurse -file) | where-object { $_.directory.name -notin $excludedFiles } 

这是我所做的,我需要将一堆备份文件复制到networking上的一个单独的位置,以便客户端提取。 我们不希望他们有上面的系统数据库备份。

我有一个类似的问题扩大这一点。 我想要一个解决scheme工作的来源,如

 $source = "D:\scripts\*.sql" 

太。 我发现这个解决scheme:

 function Copy-ToCreateFolder { param( [string]$src, [string]$dest, $exclude, [switch]$Recurse ) # The problem with Copy-Item -Rec -Exclude is that -exclude effects only top-level files # Copy-Item $src $dest -Exclude $exclude -EA silentlycontinue -Recurse:$recurse # http://stackoverflow.com/questions/731752/exclude-list-in-powershell-copy-item-does-not-appear-to-be-working if (Test-Path($src)) { # Nonstandard: I create destination directories on the fly [void](New-Item $dest -itemtype directory -EA silentlycontinue ) Get-ChildItem -Path $src -Force -exclude $exclude | % { if ($_.psIsContainer) { if ($Recurse) # Non-standard: I don't want to copy empty directories { $sub = $_ $p = Split-path $sub $currentfolder = Split-Path $sub -leaf #Get-ChildItem $_ -rec -name -exclude $exclude -Force | % { "{0} {1}" -f $p, "$currentfolder\$_" } [void](New-item $dest\$currentfolder -type directory -ea silentlycontinue) Get-ChildItem $_ -Recurse:$Recurse -name -exclude $exclude -Force | % { Copy-item $sub\$_ $dest\$currentfolder\$_ } } } else { #"{0} {1}" -f (split-path $_.fullname), (split-path $_.fullname -leaf) Copy-Item $_ $dest } } } }