使用 PowerShell 归档没有某些子文件夹和文件的文件夹
Archive folder without some subfolders and files using PowerShell
我需要使用 PowerShell 归档一个没有子文件夹和文件的文件夹。我的 file/folder 排除可以发生在任何层级。为了解释,这里有一个 WinForms VS 项目的简单示例。如果我们在 VS 中打开它并构建,VS 会创建包含可执行内容的 bin/obj 子文件夹、包含用户设置的隐藏 .vs 文件夹,以及可能包含在解决方案中的项目的 *.user 文件。我想归档这样一个 VS 解决方案文件夹,而没有所有那些可以在我们下次构建解决方案时重新创建的文件和文件夹项目。
使用 7-Zip 的 -x 可以轻松完成!命令行开关:
"C:\Program Files-Zipz.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 in my script or try to filter the files/folders using Where-Object,我将丢失存档中的文件夹层次结构。
我的问题有解决方案吗?我需要在没有任何外部工具的情况下仅使用 PowerShell 来解决问题。
这是一个与 类似的问题。
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
我需要使用 PowerShell 归档一个没有子文件夹和文件的文件夹。我的 file/folder 排除可以发生在任何层级。为了解释,这里有一个 WinForms VS 项目的简单示例。如果我们在 VS 中打开它并构建,VS 会创建包含可执行内容的 bin/obj 子文件夹、包含用户设置的隐藏 .vs 文件夹,以及可能包含在解决方案中的项目的 *.user 文件。我想归档这样一个 VS 解决方案文件夹,而没有所有那些可以在我们下次构建解决方案时重新创建的文件和文件夹项目。
使用 7-Zip 的 -x 可以轻松完成!命令行开关:
"C:\Program Files-Zipz.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 in my script or try to filter the files/folders using Where-Object,我将丢失存档中的文件夹层次结构。
我的问题有解决方案吗?我需要在没有任何外部工具的情况下仅使用 PowerShell 来解决问题。
这是一个与
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