【问题标题】:Copy-Item does not copy to correct target directoryCopy-Item 不复制到正确的目标目录
【发布时间】:2019-05-24 23:57:49
【问题描述】:

我正在尝试使用 PowerShell 脚本复制目录结构。我希望排除某个目录。

我的目录结构如下:

C:\
└───murks
    ├───murks_source
    │   │   test1.txt
    │   │   test2.txt
    │   │
    │   ├───sub
    │   │       subtest1.txt
    │   │       subtest2.txt
    │   │       subtest3.txt
    │   │
    │   └───sub2
    │           sub2test.txt
    │
    └───murks_target

现在,当我运行脚本时,它不会使用从属文件创建子目录“sub2”。相反,它将所有文件(也包括“sub2”子目录的文件)直接复制到 murks_target_directory 中。我不明白这种行为,因为“Select -ExpandProperty FullName”部分到目前为止看起来不错。

非常感谢任何帮助或提示。 提前致谢!

到目前为止,我的脚本如下所示:

$rootFolderPath = 'C:\murks\murks_source'
$excludeDirectories = ("sub");

function Exclude-Directories
{
    process
    {
        $allowThrough = $true
        foreach ($directoryToExclude in $excludeDirectories)
        {
            $directoryText = "*\" + $directoryToExclude
            $childText = "*\" + $directoryToExclude + "\*"
            if (($_.FullName -Like $directoryText -And $_.PsIsContainer) `
                -Or $_.FullName -Like $childText)
            {
                $allowThrough = $false
                break
            }
        }

        if ($allowThrough)
        {
            return $_
        }
    }
}

Get-ChildItem $rootFolderPath -Recurse | Exclude-Directories | Select -ExpandProperty FullName | Copy-Item -Destination C:\murks\murks_target -Force

【问题讨论】:

  • 问题是你的平面-Destination,Copy-Item 完全按照你的指示去做。
  • 顺便说一句,不要重新发明轮子,使用robocopy 'C:\murks\murks_source' 'C:\murks\murks_target' * /XD "sub" /S
  • 嘿伙计。也许通过你的选择当然并选择一个答案??????????

标签: powershell copy-item


【解决方案1】:

这些都可以通过单行来实现。

$source = 'C:\murks\murks_source'
$dest = 'C:\murks\murks_target'

复制除“子”文件夹及其内容之外的所有内容:

Get-ChildItem -Path $source -Recurse | ? {$_.Name -notmatch 'sub'} | Copy-Item -Destination $dest

保留包含所有文件的文件夹结构:

Get-ChildItem -Path $source | Copy-Item -Destination $dest -Recurse -Container

复制文件夹结构但没有文件...

Get-ChildItem -Path $source | ? {$_.PSIsContainer} | Copy-Item -Destination $dest -Recurse -Exclude '*.*'

您显然可以结合示例 1 和示例 2 来保留文件夹/文件结构,并通过名称、通配符等排除您想要的任何目录。

【讨论】:

  • 一个简单的正则表达式 'sub' 也将排除 sub2 xsub 等。一个更复杂的正则表达式可能会做 (?<=\\|^)sub(?=\\|$) 但要排除的文件夹来自一个数组。主要问题也是平坦的目的地。
  • 对。这只是一个例子。除了“排除目录”之外,我什至不清楚 OP 想要什么。如果那是他们知道名称的一个目录,则将其插入。否则以这个为例并收紧以供您使用。
  • 这是我帮助解决的问题:“相反,它会将所有文件(也包括“sub2”子目录的文件)直接复制到 murks_target_directory 中。”
  • @LotPings 使用 -Container 轻松解决了平面问题。
  • 是的,不递归源并使用带有 Copy-Item 的 -Container 参数就可以了,只是不包括 sub 缺失 => gci $source|? Name -ne 'sub'|Copy-Item -Dest $dest -Rec -Container
【解决方案2】:

下面的自定义函数应该做你想做的:

function Copy-Path {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
        [ValidateScript({Test-Path -Path $_ -PathType Container})]
        [string]$Source,

        [Parameter(Position = 1)]
        [string]$Destination,

        [string[]]$ExcludeFolders = $null,
        [switch]$IncludeEmptyFolders
    )
    $Source      = $Source.TrimEnd("\")
    $Destination = $Destination.TrimEnd("\")

    Get-ChildItem -Path $Source -Recurse | ForEach-Object {
        if ($_.PSIsContainer) {
            # it's a folder
            if ($ExcludeFolders.Count) {
                if ($ExcludeFolders -notcontains $_.Name -and $IncludeEmptyFolders) {
                    # create the destination folder, even if it is empty
                    $target = Join-Path -Path $Destination -ChildPath $_.FullName.Substring($Source.Length)
                    if (!(Test-Path $target -PathType Container)) {
                        Write-Verbose "Create folder $target"
                        New-Item -ItemType Directory -Path $target | Out-Null
                    }
                }
            }
        }
        else {
            # it's a file
            $copy = $true
            if ($ExcludeFolders.Count) {
                # get all subdirectories in the current file path as array
                $subs = $_.DirectoryName.Replace($Source,"").Trim("\").Split("\")
                # check each sub folder name against the $ExcludeFolders array
                foreach ($folderName in $subs) {
                    if ($ExcludeFolders -contains $folderName) { $copy = $false; break }
                }
            }

            if ($copy) {
                # create the destination folder if it does not exist yet
                $target = Join-Path -Path $Destination -ChildPath $_.DirectoryName.Substring($Source.Length)
                if (!(Test-Path $target -PathType Container)) {
                    Write-Verbose "Create folder $target"
                    New-Item -ItemType Directory -Path $target | Out-Null
                }
                Write-Verbose "Copy file $($_.FullName) to $target"
                $_ | Copy-Item -Destination $target -Force
            }
        }
    }
}

一旦到位,像这样使用它:

Copy-Path -Source 'C:\murks\murks_source' -Destination 'C:\murks\murks_target' -ExcludeFolders 'sub' -Verbose

参数-ExcludeFolders 可以是要跳过的文件夹名称数组。
添加开关参数IncludeEmptyFolders 也会在目标中创建空文件夹。如果省略,将不会复制空文件夹。

使用您的示例文件结构,结果是

C:\murks\murks_target
|   test1.txt
|   test2.txt
|
\---sub2
        sub2test.txt

【讨论】:

    【解决方案3】:

    几乎找到了一个可以提供您不想要的功能的答案。

    $from = "C:\murks\murks_source"
    $to = "C:\murks\murks_target"
    $exclude = Get-ChildItem -Path C:\murks\murks_source\sub2\ -Depth 10
    Copy-Item $from -Exclude $exclude -Destination $to -Recurse
    

    它将忽略除文件夹结构之外的所有文件。 文件夹结构将被复制但为空。

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-04
      • 1970-01-01
      • 2019-12-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多