使用PowerShell从zip文件中提取目录的最优雅方法?

时间:2014-07-10 09:10:10

标签: powershell

我需要从zipfile解压缩特定目录。

例如,提取目录' test \ etc \ script'来自zipfile' c:\ tmp \ test.zip'并将其放在c:\ tmp \ output \ test \ etc \ script。

以下代码有效但有两个怪癖:

  • 我需要递归地找到zip文件(函数finditem)中的目录(' script'),尽管我已经知道了路径(' c:\ tmp \ test.zip \测试\等\脚本&#39)

  • 使用CopyHere我需要确定目标目录,特别是' test \ etc'部分手动

有更好的解决方案吗?感谢。

代码:

function finditem($items, $itemname)
{
  foreach($item In $items)
  {
    if ($item.GetFolder -ne $Null)
    {
      finditem $item.GetFolder.items() $itemname
    }
    if ($item.name -Like $itemname)
    {
        return $item
    } 
  } 
} 

$source = 'c:\tmp\test.zip'
$target = 'c:\tmp\output'

$shell = new-object -com shell.application

# find script folder e.g. c:\tmp\test.zip\test\etc\script
$item = finditem $shell.NameSpace($source).Items() "script"

# output folder is c:\tmp\output\test\etc
$targetfolder = Join-Path $target ((split-path $item.path -Parent) -replace '^.*zip')
New-Item $targetfolder -ItemType directory -ErrorAction Ignore

# unzip c:\tmp\test.zip\test\etc\script to c:\tmp\output\test\etc
$shell.NameSpace($targetfolder).CopyHere($item)

3 个答案:

答案 0 :(得分:10)

我不知道最优雅,但安装了.Net 4.5,您可以使用System.IO.Compression命名空间中的ZipFile类:

[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null

$zipfile = 'C:\path\to\your.zip'
$folder  = 'folder\inside\zipfile'
$dst     = 'C:\output\folder'

[IO.Compression.ZipFile]::OpenRead($zipfile).Entries | ? {
  $_.FullName -like "$($folder -replace '\\','/')/*"
} | % {
  $file   = Join-Path $dst $_.FullName
  $parent = Split-Path -Parent $file
  if (-not (Test-Path -LiteralPath $parent)) {
    New-Item -Path $parent -Type Directory | Out-Null
  }
  [IO.Compression.ZipFileExtensions]::ExtractToFile($_, $file, $true)
}

ExtractToFile()的3 rd 参数可以省略。如果存在,它定义是否覆盖现有文件。

答案 1 :(得分:7)

只要知道zip中的文件夹位置,就可以简化原始代码:

$source = 'c:\tmp\test.zip'  # zip file
$target = 'c:\tmp\output'    # target root
$folder = 'test\etc\script'  # path in the zip

$shell = New-Object -ComObject Shell.Application

# find script folder e.g. c:\tmp\test.zip\test\etc\script
$item = $shell.NameSpace("$source\$folder")

# actual destination directory
$path = Split-Path (Join-Path $target $folder)
if (!(Test-Path $path)) {$null = mkdir $path}

# unzip c:\tmp\test.zip\test\etc\script to c:\tmp\output\test\etc\script
$shell.NameSpace($path).CopyHere($item)

答案 2 :(得分:6)

Windows PowerShell 5.0(包含在Windows 10中)本身支持使用Expand-Archive cmdlet提取ZIP文件:

Expand-Archive -Path Draft.Zip -DestinationPath C:\Reference