วิธีการแตกไฟล์ใน 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
ในทางทฤษฎีคุณทำไม่ได้ ฉันพยายามซ่อนการโทรที่ซับซ้อน / ไม่เป็นทางการในฟังก์ชั่นดังนั้นภายหลังฉันสามารถแทนที่วิธีได้โดยไม่ต้องกังวลว่าจะใช้ที่ใด ดังที่ Keith พูดถึงใน V5 จะมีวิธีการใหม่ในการทำ
Micky Balladelli

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 แต่ฉันไม่ได้คิดออกว่าทำไมฉันถึงได้รับข้อผิดพลาดนี้
Sam

500

ใน PowerShell v5 + มีคำสั่ง Expand-Archive (รวมถึง Compress-Archive) ในตัว:

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

26
ใช้$PSVersionTable.PSVersionเพื่อกำหนด PowerShell รุ่นที่คุณใช้
แบรด C

1
@ LoneCoder ฉันไม่คิดว่าคุณจะโทษ Ballmer ได้ 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
ไม่มีความแตกต่างระหว่าง v5 และ v5.1 ใน Cmdlet นี้ คุณไม่จำเป็นต้องตั้งชื่อพารามิเตอร์แรก มันจะกลายเป็นเส้นทางโดยอัตโนมัติ ตัวอย่างเช่นExpand-Archive Draft.Zip -DestinationPath C:\Referenceทำงานได้โดยไม่มีปัญหา นอกจากนี้มันไม่ใช่เส้นทางที่แท้จริงแต่เป็นเส้นทางที่แน่นอน
Franklin Yu

13

ใช้Expand-Archivecmdlet กับหนึ่งในชุดพารามิเตอร์:

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
หากหนึ่งในไฟล์หรือไดเรกทอรีที่มีอยู่แล้วในสถานที่ปลายทางมันปรากฏขึ้นการเจรจาถามว่าจะทำอย่างไร (เพิกเฉยเขียนทับ) ซึ่งเอาชนะวัตถุประสงค์ ไม่มีใครรู้วิธีการบังคับให้เขียนทับเงียบ ๆ ?
Oleg Kazakov

ตอบกลับความคิดเห็นโดย @OlegKazakov: มีชุดตัวเลือกในการควบคุมCopyHereวิธีการ ฉันเดา @OlegKazakov แก้ไขปัญหาของเขาแล้ว อย่างไรก็ตามฉันใส่ลิงค์นี้ที่นี่สำหรับนักเล่นคนอื่น ๆ ที่สามารถค้นหาหัวข้อนี้: docs.microsoft.com/en-us/previous-versions/windows/desktop/ ......
jsxt

4

สำหรับผู้ที่ต้องการใช้Shell.Application.Namespace.Folder.CopyHere ()และต้องการซ่อนแถบความคืบหน้าขณะคัดลอกหรือใช้ตัวเลือกเพิ่มเติมเอกสารมีอยู่ที่นี่:
https://docs.microsoft.com/en-us / Windows / สก์ท็อป / เปลือก / โฟลเดอร์ 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)

ข้อ จำกัด ในการใช้งาน Shell.Application บน windows core version:
https://docs.microsoft.com/en-us/windows-server/administrator/server-core/what-is-server-core

บน windows core version โดยค่าเริ่มต้น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
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.