Як розпакувати файл у Powershell?


224

У мене є .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все ще порожній.


6
Якщо ви встановлені в Powershell 2.0 або без .NET 4.5, то вказаний вами метод - це єдиний шлях (без переходу з стороннім exe (тобто 7zip). Я б сказав, що на це питання не знайдено повного відповіді, поки хтось надає, чому цей метод не працює. Мені він час від часу працює, а іншим
kenny

Відповіді:


248

Ось простий спосіб використання ExtractToDirectory від System.IO.Compression.ZipFile :

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 створить її. Інші застереження:

Дивитися також:


10
Чому ви створюєте функцію для заміни одного виклику функції?

17
Теоретично ви цього не робите. Я намагаюся приховати складні / нетрадиційні виклики у функціях, щоб пізніше я міг замінити метод, не переживаючи, де він використовується. Як згадував Кіт, у V5 з'явиться новий спосіб зробити це.
Міккі Баладделлі

1
Для цього вам потрібно щонайменше .NET Framework 4.5. Дивіться внизу msdn.microsoft.com/en-us/library/…
ferventcoder

10
Я спробував це, але потрапив нижче помилки, 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
Karthi1234

4
Це дає мені таку помилку: Add-Type : Cannot add type. The assembly 'System.IO.Compression.FileSystem' could not be found. . У мене встановлено .NET 4.6.2, і я перевірив, що збірка знаходиться в GAC, але я не з'ясував, чому я отримую цю помилку.
Сем

500

У PowerShell v5 + є вбудована команда Expand-Archive (а також Compress-Archive):

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

26
Використовуйте, $PSVersionTable.PSVersionщоб визначити, яку версію PowerShell ви використовуєте.
Бред С

1
@LoneCoder Я не думаю, що ти можеш звинувачувати Баллмера. Windows ніколи не мав вбудованого інструмента командного рядка для обробки стислих файлів, навіть якщо gzip вийшов у 1992 році, а tar вже старіший.
jpmc26

2
@Ghashange PowerShell 5 навіть не була доступна для нічого нижче Windows 10 та Server 2012, коли ця відповідь була розміщена, навіть як попередній випуск.
jpmc26

11
Схоже, параметр OutputPathбуло змінено на DestinationPath(посилання msdn.microsoft.com/powershell/reference/5.1/… )
Elijah W. Gagne

1
Ви також можете використовувати відносні шляхи на зразокExpand-Archive -Path .\a.zip -DestinationPath .
Culip

24

У PowerShell v5.1 це дещо інше порівняно з v5. Згідно з документацією на MS, він повинен мати -Pathпараметр, щоб вказати шлях до файлу архіву.

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

Або ж це може бути фактичний шлях:

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

Розгорнути-Архів Док


3
У цьому Cmdlet немає різниці між v5 та v5.1. Вам не потрібно називати перший параметр; він автоматично стане шляхом. Наприклад, Expand-Archive Draft.Zip -DestinationPath C:\Referenceпрацює без проблем. Крім того, це не власне шлях, а абсолютний шлях.
Франклін Ю

13

Використовуйте Expand-Archiveкомандлет з одним із наборів параметрів:

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

12

Ей, це працює для мене ..

$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)
}

2
Якщо один із файлів або каталогів уже існує у місці призначення, він вискакує діалог із запитанням, що робити (ігнорувати, перезаписувати), що перемагає мету. Хтось знає, як змусити його мовчки переписувати?
Олег Казаков

Відповідаючи на коментар @OlegKazakov: існує безліч варіантів, що контролюють CopyHereметод. Гадаю, @OlegKazakov вже вирішив своє питання. Тим не менш, я посилаю
jsxt

4

Для тих, хто хоче використовувати Shell.Application.Namespace.Folder.CopyHere () і хочуть приховати смуги прогресу під час копіювання або використовувати додаткові параметри, документація тут:
https://docs.microsoft.com/en-us / windows / desktop / shell / folder-copyhere

Щоб використовувати панель повноважень та приховати смужки прогресу та відключити підтвердження, ви можете використовувати такий код:

# 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)

Обмеження використання Shell.Application на основні версії Windows:
https://docs.microsoft.com/en-us/windows-server/administration/server-core/what-is-server-core

У базових версіях Windows за замовчуванням Microsoft-Windows-Server-Shell-Package не встановлено, тому shell.applicaton не працюватиме.

Примітка : Витяг архівів таким чином займе багато часу і може сповільнити Windows Gui


3

Використання, expand-archiveале автоматичне створення каталогів, імені архіву:

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

Це обов'язково розширюється в поточному каталозі, чи не так?
jpmc26

Не реально бачити додану вартість автоматичного створення. Гнучкіше додати другий параметр, outputPathяк у прийнятій відповіді. У цьому рішенні (як сказав jpmc26) ви завжди створюватимете новий каталог у поточному каталозі, тому можливо вам потрібно встановити поточний каталог перед тим, як дзвонитиunzip
Rubanov

Більшість архіваторів витягують у dir, названий на честь архіву, там же, де і архів. Ніщо не заважає вам додавати параметри, якщо ви хочете щось інше, але це розумний дефолт.
mikemaccana

1
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наприкінці
tom.maruska

0

ForEachЦикл обробляє кожен ZIP-файл, який знаходиться в межах $filepathзмінної

    foreach($file in $filepath)
    {
        $zip = $shell.NameSpace($file.FullName)
        foreach($item in $zip.items())
        {
            $shell.Namespace($file.DirectoryName).copyhere($item)
        }
        Remove-Item $file.FullName
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.