【问题标题】:How to unzip a file in Powershell?如何在 Powershell 中解压缩文件?
【发布时间】:2015-03-02 07:52:33
【问题描述】:

我有一个.zip 文件,需要使用 Powershell 解压缩其全部内容。我正在这样做,但它似乎不起作用:

$shell = New-Object -ComObject shell.application
$zip = $shell.NameSpace("C:\a.zip")
MkDir("C:\a")
foreach ($item in $zip.items()) {
  $shell.Namespace("C:\a").CopyHere($item)
}

怎么了?目录C:\a 还是空的。

【问题讨论】:

  • 如果您使用的是 Powershell 2.0,或者没有安装 .NET 4.5,那么您提到的方法是唯一的路径(不使用第 3 方 exe(即 7zip)。我会说直到有人提供为什么这种方法不起作用,这个问题才得到完全回答。有时它对我有用,但其他时候却没有。
  • 由于 Expand-Archive 现在存在于 powershell 中,因此接受的答案有点过时了。

标签: powershell


【解决方案1】:

这是使用来自System.IO.Compression.ZipFileExtractToDirectory 的简单方法:

Add-Type -AssemblyName System.IO.Compression.FileSystem
function Unzip
{
    param([string]$zipfile, [string]$outpath)

    [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
}

Unzip "C:\a.zip" "C:\a"

请注意,如果目标文件夹不存在,ExtractToDirectory 将创建它。其他注意事项:

另见:

【讨论】:

  • 除非路径中有空格,否则不需要引用参数C:\a.zip或C:\a。 PowerShell 将参数视为字符串或数字类型,除非参数以 $、@、( 或 { 等特殊字符开头。这是 PowerShell 作为shell 脚本语言的好处之一。:-)
  • 为什么要创建一个函数来替换单个函数调用?
  • 理论上你不会。我尝试在函数中隐藏复杂/非常规的调用,以便稍后我可以替换该方法而不必担心它的使用位置。正如 Keith 提到的,在 V5 中将会有一种新的方式来做到这一点。
  • 我试过了,但出现以下错误,Exception calling "ExtractToDirectory" with "2" argument(s): "End of Central Directory record could not be found." At line:5 char:5 + [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $ou ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : InvalidDataException
  • 这给了我以下错误:Add-Type : Cannot add type. The assembly 'System.IO.Compression.FileSystem' could not be found.。我安装了 .NET 4.6.2,并且我已验证程序集在 GAC 中,但我不知道为什么会出现此错误。
【解决方案2】:

在 PowerShell v5+ 中,内置了一个 Expand-Archive command(以及 Compress-Archive):

Expand-Archive c:\a.zip -DestinationPath c:\a

【讨论】:

  • 使用 $PSVersionTable.PSVersion 确定您正在运行的 PowerShell 版本。
  • @Ghashange PowerShell 5 在发布此答案时甚至不适用于 Windows 10 和 Server 2012 以下的任何版本,即使作为预发布版本也是如此。
  • 参数OutputPath好像改成了DestinationPath(参考msdn.microsoft.com/powershell/reference/5.1/…
  • 你也可以使用相对路径,比如Expand-Archive -Path .\a.zip -DestinationPath .
  • 注意Expand-ArchiveCompress-Archive要求存档文件扩展名是.zip,而基于[System.IO.Compression.ZipFile]的解决方案不需要。
【解决方案3】:

嘿,它对我有用..

$shell = New-Object -ComObject shell.application
$zip = $shell.NameSpace("put ur zip file path here")
foreach ($item in $zip.items()) {
  $shell.Namespace("destination where files need to unzip").CopyHere($item)
}

【讨论】:

  • 如果其中一个文件或目录已经存在于目标位置,它会弹出一个对话框,询问要做什么(忽略、覆盖),这违背了目的。有谁知道如何强制它静默覆盖?
  • 回答@OlegKazakov 的评论:有一组选项控制CopyHere 方法。我猜@OlegKazakov 已经解决了他的问题。尽管如此,我还是将此链接放在这里以供其他可以找到此主题的冲浪者使用:docs.microsoft.com/en-us/previous-versions/windows/desktop/…
【解决方案4】:

使用expand-archive,但自动创建以存档命名的目录:

function unzip ($file) {
    $dirname = (Get-Item $file).Basename
    New-Item -Force -ItemType directory -Path $dirname
    expand-archive $file -OutputPath $dirname -ShowProgress
}

【讨论】:

  • 这必然会在当前目录中展开,不是吗?
  • 没有真正看到自动创建的附加值。在接受的答案中添加第二个参数outputPath 会更加灵活。在此解决方案中(如 jpmc26 所说),您将始终在当前目录中创建一个新目录,因此您可能需要在调用 unzip 之前设置当前目录
  • 大多数存档器提取到以存档命名的目录中,与存档位于同一位置。如果您想要不同的东西,没有什么可以阻止您添加参数,但这是一个明智的默认设置。
【解决方案5】:

在 PowerShell v5.1 中,这与 v5 略有不同。根据 MS 文档,它必须有一个 -Path 参数来指定存档文件路径。

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

否则,这可以是一条实际路径:

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

Expand-Archive Doc

【讨论】:

  • 这个 Cmdlet 中 v5 和 v5.1 没有区别。您不需要命名第一个参数;它会自动成为路径。例如,Expand-Archive Draft.Zip -DestinationPath C:\Reference 可以正常工作。另外,不是实际路径,而是绝对路径。
【解决方案6】:
function unzip {
    param (
        [string]$archiveFilePath,
        [string]$destinationPath
    )

    if ($archiveFilePath -notlike '?:\*') {
        $archiveFilePath = [System.IO.Path]::Combine($PWD, $archiveFilePath)
    }

    if ($destinationPath -notlike '?:\*') {
        $destinationPath = [System.IO.Path]::Combine($PWD, $destinationPath)
    }

    Add-Type -AssemblyName System.IO.Compression
    Add-Type -AssemblyName System.IO.Compression.FileSystem

    $archiveFile = [System.IO.File]::Open($archiveFilePath, [System.IO.FileMode]::Open)
    $archive = [System.IO.Compression.ZipArchive]::new($archiveFile)

    if (Test-Path $destinationPath) {
        foreach ($item in $archive.Entries) {
            $destinationItemPath = [System.IO.Path]::Combine($destinationPath, $item.FullName)

            if ($destinationItemPath -like '*/') {
                New-Item $destinationItemPath -Force -ItemType Directory > $null
            } else {
                New-Item $destinationItemPath -Force -ItemType File > $null

                [System.IO.Compression.ZipFileExtensions]::ExtractToFile($item, $destinationItemPath, $true)
            }
        }
    } else {
        [System.IO.Compression.ZipFileExtensions]::ExtractToDirectory($archive, $destinationPath)
    }
}

使用:

unzip 'Applications\Site.zip' 'C:\inetpub\wwwroot\Site'

【讨论】:

  • 别忘了把$archive$archiveFile放在最后
【解决方案7】:

对于那些想要使用 Shell.Application.Namespace.Folder.CopyHere() 并希望在复制时隐藏进度条或使用更多选项的人,文档在这里:
https://docs.microsoft.com/en-us/windows/desktop/shell/folder-copyhere

要使用 powershell 并隐藏进度条并禁用确认,您可以使用如下代码:

# We should create folder before using it for shell operations as it is required
New-Item -ItemType directory -Path "C:\destinationDir" -Force

$shell = New-Object -ComObject Shell.Application
$zip = $shell.Namespace("C:\archive.zip")
$items = $zip.items()
$shell.Namespace("C:\destinationDir").CopyHere($items, 1556)

在 windows 核心版本上使用 Shell.Application 的限制:
https://docs.microsoft.com/en-us/windows-server/administration/server-core/what-is-server-core

在 Windows core 版本上,默认情况下未安装 Microsoft-Windows-Server-Shell-Package,因此 shell.applicon 将不起作用。

注意:以这种方式提取档案需要很长时间,并且会减慢 windows gui

【讨论】:

    【解决方案8】:

    使用Expand-Archive cmdlet 和参数集之一:

    Expand-Archive -LiteralPath C:\source\file.Zip -DestinationPath C:\destination
    
    Expand-Archive -Path file.Zip -DestinationPath C:\destination
    

    【讨论】:

      【解决方案9】:

      ForEach 循环处理位于$filepath 变量中的每个 ZIP 文件

          foreach($file in $filepath)
          {
              $zip = $shell.NameSpace($file.FullName)
              foreach($item in $zip.items())
              {
                  $shell.Namespace($file.DirectoryName).copyhere($item)
              }
              Remove-Item $file.FullName
          }
      

      【讨论】:

        【解决方案10】:

        使用内置的powershell方法Expand-Archive

        例子

        Expand-Archive -LiteralPath C:\archive.zip -DestinationPath C:\
        

        【讨论】:

          猜你喜欢
          • 2021-09-12
          • 2011-10-30
          • 1970-01-01
          • 1970-01-01
          • 2011-11-15
          • 2014-06-12
          • 2017-11-03
          • 2016-10-15
          • 1970-01-01
          相关资源
          最近更新 更多