2009-04-08 21 views
57

我已经PowerShell脚本的以下片段:排除在PowerShell中拷贝项目列表不出现奏效

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

其中一期工程的所有文件和文件夹从T1复制到t2,但它只排除排除“根”/“第一级”文件夹中的列表,而不是在子文件夹中。

如何让它排除所有文件夹中的排除列表?

回答

80

我认为最好的方法是在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)} 

基本上,这里发生了什么是你正在通过有效的文件会一个接一个,然后将它们复制到新的路径。最后的'Join-Path'语句是为了在复制文件时保留目录。该部分采用目标目录并将其与源路径之后的目录连接。

我从here得到了想法,然后对它进行了一些修改,使其适用于本示例。

我希望它的作品!

+1

这只是我要发布解决方案的预期问题的片段。 :)我发现-Include和-Exclude对于Select-String,Copy-Item和其他一些命令不起作用。它适用于Get-ChildItem(dir)。 – JasonMArcher 2009-04-09 00:01:10

+0

IIRC,如果您查看这些cmdlet的帮助文件,则表明这些参数无法按预期工作。出货是选择。 – 2009-04-09 14:42:53

+0

谢谢亚伦 - 完美的工作! – Guy 2009-04-09 19:10:29

1

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

使用landyman的提示和我在其他地方找到的东西,我发现它工作正常:

$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)} 
5

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)} 
0

我有一个类似的问题扩大了这一点。我想要一个解决方案的工作,如

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

也。我发现这个解决方案:

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 
      } 
     } 
    } 
} 
4

为注释格式代码厉害,我会后的答案,但它只是一个除了@ landyman的答案。 建议的脚本有一个缺点 - 它会创建双嵌套文件夹。例如,对于'd:\ t1 \ sub1',它将创建空目录'd:\ t2 \ sub1 \ sub1'。这是由于目录的Copy-Item需要-Destination属性中的父目录名称而不是目录名称本身。 这里有一个解决方法,我发现:

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) 
     } 
     } 
1

获取-ChildItem与联接路径是工作主要是为我,但我意识到这是抄袭其他根目录下,这是不好的内部根目录。

例如

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

  • 源目录:C:\ SomeFolder \ CopyInHere

  • 目标目录:d:\ PutItInHere

目标: 复制每childitem内C:\ SomeFolder \ CopyInHere到d根:\ PutItInHere,但不包括C:\ SomeFolder \ CopyInHere本身。
- 例如带上CopyInHere的所有孩子,让他们成为PutItInere的儿童

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

这是因为加入路径计算SubFolder子项的d:\ PutItInHere \ SubFolder的目标路径,所以SubFolder get的创建在名为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对象。如果是,它会检查父文件夹是否为源目录,这意味着当前正在迭代的文件夹是源目录的直接子目录,因此我们不应将其名称附加到目标目录,因为我们希望该文件夹是在目标目录中创建,而不是在目标目录中的文件夹中创建。

接下来,其他每个文件夹都会正常工作。

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

这就是我所做的,我需要将一堆备份文件复制到网络上的一个单独位置以供客户端接取。我们不希望他们拥有上述系统数据库备份。

4

我也有这个问题,花了20分钟在这里应用解决方案,但一直有问题。
所以我选择使用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 

此外,它具有吨的功能,如可恢复副本。 Docs here

0

从现在作为在PowerShell中5