代码之家  ›  专栏  ›  技术社区  ›  TecMan

使用PowerShell存档没有子文件夹和文件的文件夹

  •  0
  • TecMan  · 技术社区  · 3 年前

    我需要使用PowerShell归档一个没有子文件夹和文件的文件夹。“我的文件夹”的任何层次结构都可以发生“排除”。下面是WinForms VS项目的一个简单示例。如果我们在VS和build中打开它,VS将创建包含可执行内容的bin/obj子文件夹,即隐藏的。带用户设置的vs文件夹,可能还有*。解决方案中包含的项目的用户文件。我想归档这样一个VS solution文件夹,而不需要下一次构建解决方案时可以重新创建的所有文件和文件夹项。

    这是非常容易做到的7-Zip使用它的-x!命令行开关:

    "C:\Program Files\7-Zip\7z.exe" a -tzip "D:\Temp\WindowsFormsApp1.zip" "D:\Temp\WindowsFormsApp1\"  -r -x!bin -x!obj -x!.vs -x!*.suo -x!*.user
    

    然而,我无法构建等效的PowerShell脚本。我得到的最好的东西是这样的:

    $exclude = "bin", "obj", ".vs", "*.suo", "*.user"
    $files = Get-ChildItem -Path $path -Exclude $exclude -Force
    Compress-Archive -Path $files -DestinationPath $dest -Force
    

    如果执行此脚本,排除列表仅适用于第一层次结构级别的子文件夹。如果我将-Recurse开关添加到 Get-ChildItem cmdlet或尝试使用 Where-Object ,我丢失了存档中的文件夹层次结构。

    有办法解决我的问题吗?我需要在没有任何外部工具的情况下单独使用PowerShell来解决这个问题。

    0 回复  |  直到 3 年前
        1
  •  2
  •   Rich Moss    3 年前

    这是一个类似的问题 how-to-compress-log-files-older-than-30-days-in-windows .

    这个 ArchiveOldLogs.ps1 脚本将保留文件夹结构,无需中间复制。

    你可以改变主意 -Filter 按名称而不是日期排除某些文件的参数:

    $filter = {($_.Name -notlike '*.vs') -and ($_.Name -notlike '*.suo') -and ($_.Name -notlike '*.user') -and ($_.FullName -notlike '*bin\*') -and ($_.FullName -notlike '*obj\*')}
    .\ArchiveOldLogs.ps1 -FileSpecs @('*.*') -Filter $filter -DeleteAfterArchiving:$false
    

    下面是一个简单的示例,它不包括精美的进度条,不防止存档中出现重复,也不删除存档文件:

    $ParentFolder = 'C:\projects\Code\' #files will be stored with a path relative to this folder
    $ZipPath = 'c:\temp\projects.zip' #the zip file should not be under $ParentFolder or an exception will be raised
    $filter = {($_.Name -notlike '*.vs') -and ($_.Name -notlike '*.suo') -and ($_.Name -notlike '*.user') -and ($_.FullName -notlike '*bin\*') -and ($_.FullName -notlike '*obj\*')}
    @( 'System.IO.Compression','System.IO.Compression.FileSystem') | % { [void][Reflection.Assembly]::LoadWithPartialName($_) }
    Push-Location $ParentFolder #change to the parent folder so we can get $RelativePath
    $FileList = (Get-ChildItem '*.*' -File -Recurse | Where-Object $Filter) #use the -File argument because empty folders can't be stored
    Try{
        $WriteArchive = [IO.Compression.ZipFile]::Open( $ZipPath,'Update')
        ForEach ($File in $FileList){
            $RelativePath = (Resolve-Path -LiteralPath "$($File.FullName)" -Relative) -replace '^.\\' #trim leading .\ from path 
            Try{    
                [IO.Compression.ZipFileExtensions]::CreateEntryFromFile($WriteArchive, $File.FullName, $RelativePath, 'Optimal').FullName
            }Catch{ #Single file failed - usually inaccessible or in use
                Write-Warning  "$($File.FullName) could not be archived. `n $($_.Exception.Message)"  
            }
        }
    }Catch [Exception]{ #failure to open the zip file
        Write-Error $_.Exception
    }Finally{
        $WriteArchive.Dispose() #always close the zip file so it can be read later 
    }
    Pop-Location