Powershell复制带有黑名单(排除)和白名单(包括)的文件

时间:2017-03-15 18:33:35

标签: powershell powershell-v5.0

我正在将一些msbuild脚本翻译成powershell。

在msbuild中,我可以生成我想要(递归)复制到目标文件夹的文件的黑名单和/或白名单。

如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="AllTargetsWrapped">

    <PropertyGroup>
        <!-- Always declare some kind of "base directory" and then work off of that in the majority of cases  -->
        <WorkingCheckout>.</WorkingCheckout>
        <WindowsSystem32Directory>c:\windows\System32</WindowsSystem32Directory>
        <ArtifactDestinationFolder>$(WorkingCheckout)\ZZZArtifacts</ArtifactDestinationFolder>
    </PropertyGroup>

    <Target Name="AllTargetsWrapped">

        <CallTarget Targets="CleanArtifactFolder" />
        <CallTarget Targets="CopyFilesToArtifactFolder" />
    </Target>

    <Target Name="CleanArtifactFolder">

        <RemoveDir Directories="$(ArtifactDestinationFolder)" Condition="Exists($(ArtifactDestinationFolder))"/>
        <MakeDir Directories="$(ArtifactDestinationFolder)" Condition="!Exists($(ArtifactDestinationFolder))"/>
        <Message Text="Cleaning done" />
    </Target>

    <Target Name="CopyFilesToArtifactFolder">

        <ItemGroup>
            <MyExcludeFiles Include="$(WindowsSystem32Directory)\**\EventViewer_EventDetails.xsl" />
        </ItemGroup>

        <ItemGroup>
            <MyIncludeFiles Include="$(WindowsSystem32Directory)\**\*.xsl" Exclude="@(MyExcludeFiles)"/>
            <MyIncludeFiles Include="$(WindowsSystem32Directory)\**\*.xslt" Exclude="@(MyExcludeFiles)"/>
            <MyIncludeFiles Include="$(WindowsSystem32Directory)\**\*.png" Exclude="@(MyExcludeFiles)"/>
            <MyIncludeFiles Include="$(WindowsSystem32Directory)\**\*.jpg" Exclude="@(MyExcludeFiles)"/>            
        </ItemGroup>        

        <Copy
                SourceFiles="@(MyIncludeFiles)"
                DestinationFiles="@(MyIncludeFiles->'$(ArtifactDestinationFolder)\%(RecursiveDir)%(Filename)%(Extension)')"
        />

        </Target>

    </Project>

我可以在PowerShell中执行相同操作吗?

我已尝试过以下内容,但它会创建一个名为&#34; C:\ work9 \ MsBuildExamples \ FileCopyRecursive \ PowershellResults&#34; (它的文件没有扩展名,不是目录)

$sourceDirectory = 'c:\windows\System32\*'
$destinationDirectory = 'C:\work9\MsBuildExamples\FileCopyRecursive\PowershellResults'
$excludeFiles = @('EventViewer_EventDetails.xsl')
$includeFiles = @('*.xsl','*.xslt','*.png','*.jpg')


Copy-Item $sourceDirectory $destinationDirectory -Recurse -Include $includeFiles -Exclude $excludeFiles
# -Container:$false

APPEND:

我试过了:

$sourceDirectory = 'c:\windows\System32'
$destinationDirectory = 'C:\work9\MsBuildExamples\FileCopyRecursive\PowershellResults'
$excludeFiles = @('EventViewer_EventDetails.xsl')
$includeFiles = @('*.xsl','*.xslt','*.png','*.jpg')


Copy-Item $sourceDirectory $destinationDirectory -Recurse -Include $includeFiles -Exclude $excludeFiles

(没有结果,甚至没有扩展名的文件)

我试过这个:

$sourceDirectory = 'c:\windows\System32'
$destinationDirectory = 'C:\work9\MsBuildExamples\FileCopyRecursive\PowershellResults'
$excludeFiles = @('EventViewer_EventDetails.xsl')
$includeFiles = @('*.xsl','*.xslt','*.png','*.jpg')


Copy-Item $sourceDirectory $destinationDirectory -Recurse -Include $includeFiles -Exclude $excludeFiles -Container:$false

(没有结果,甚至没有扩展名的文件)

3 个答案:

答案 0 :(得分:4)

Copy-Item -Recurse ,自Windows PowerShell v5.1 / PowerShell Core 6.2.0起,有怪癖和限制;这是我发现的:

如果您有其他信息或更正,请告诉我们。

有两种基本的方式来调用 Copy-Item -Recurse

  • (a)指定目录路径作为来源 - c:\windows\system32

  • (b)使用通配符表达式作为解析源目录中的多个项目的来源 - c:\windows\system32\*

    < / LI>

有两个基本问题

  • 根据目标目录是否已存在 ,复制行为会有所不同 - 请参阅下文。

  • -Include参数无效-Exclude也不正常,但-Include更有可能出现问题;见this GitHub issue

如果您需要使用-Include ,请勿使用以下解决方案 - 如果确实需要-Include,请使用LotPing's helpful solution

案例(a) - 作为源的单个目录路径

如果源是单个目录(或者是通配符模式解析为的项目中唯一的目录),Copy-Item也会隐式地将目标解释为目录。

但是,如果目标目录已存在,则复制的项目将放在以目录命名的子目录,在您的情况下意味着:C:\work9\MsBuildExamples\FileCopyRecursive\PowershellResults\System32

有一个issue in the PowerShell GitHub repository - 正当地 - 抱怨这种反直觉行为。

有两种基本的解决方法

如果可以接受,首先删除目标目录(如果存在) - 显然需要注意(一旦您有信心,请删除-WhatIf该命令按预期工作):

# Remove a pre-existing destination directory:
if (Test-Path $destinationDirectory) {
  Remove-Item $destinationDirectory -Recurse -WhatIf
}

# Now Copy-Item -Recurse works as intended.
# As stated, -Exclude works as intended, but -Include does NOT.
Copy-Item $sourceDirectory $destinationDirectory -Recurse

警告Remove-Item -Recurse,令人遗憾的是,可以间歇性地异步行动,甚至可能失败 - 有关强大的替代方案,请参阅this answer

如果您想保留 预先存在的目标目录 - 例如,如果您想添加到目标目录的内容,

  • 创建目标目录。一经请求;也就是说,只有在它尚不存在时才创建它。
  • 使用Copy-Item将源目录的内容复制到目标目录。
# Ensure that the target dir. exists.
# -Force is a quiet no-op, if it already exists.
$null = New-Item -Force -ItemType Directory -LiteralPath $destinationDirectory

# Copy the *contents* of the source directory to the target, using
# a wildcard.
# -Force ensures that *hidden items*, if any, are included too.
# As stated, -Exclude works as intended, but -Include does NOT.
Copy-Item -Force $sourceDirectory/* $destinationDirectory -Recurse

案例(b) - 作为来源的通配符表达式

注意:

  • 如果已解析的项目中完全 1 目录,则应用与案例(a)相同的规则。

  • 否则,如果目标项目尚不存在,则行为才有问题。 - 请参阅下文。

  • 因此,解决方法确保预先目标目录存在
    New-Item -Force -Path $destinationDirectory -ItemType Directory

如果目标项目(-Destination参数)尚不存在

  • 如果已解析的项目中有 多个目录 Copy-Item会复制第一个目录,然后<第二次出现强烈>失败,出现以下错误消息:
    Container cannot be copied onto existing leaf item

  • 如果源是单个文件或仅解析为文件 ,则Copy-Item隐式将不存在的目标解释为文件 即可。
    对于多个文件,这意味着创建单个目标文件,其内容是碰巧复制的文件的内容 last - 即,数据丢失

答案 1 :(得分:3)

为了保持概述,我缩短了你的变量(并改为dst以适合我的环境)

$src = 'c:\windows\System32'
$dst = 'Q:\Test\2017-03\15\PowershellResults'
$exc = @('EventViewer_EventDetails.xsl')
$inc = @('*.xsl','*.xslt','*.png','*.jpg')

Get-ChildItem -Path $src -Rec -Inc $inc -Exc $exc -ea silentlycontinue|ForEach{
  $DestPath = $_.DirectoryName -replace [regex]::escape($src),$dst
  If (!(Test-Path $DestPath)){MkDir $DestPath}
  $_|Copy-Item -Destination $DestPath -Force
}

编辑基本上与您的示例相同,可能更密集

答案 2 :(得分:2)

使用我从这里找到的建议(“触摸”方法)

Should Copy-Item create the destination directory structure?

我得到了以下工作。

我会将这个问题留下“未答复”几天,也许有人会有更好的东西。 New-Item对我来说似乎很奇怪,因为Copy-Item不应该在Include和Exclude列表中侥幸豁免。

(根据原始问题使用变量setter)

var arraySchema = new Schema({
    property: String
});

var objectSchema = new Schema({
    arrays: [arraySchema]
});