Wie entpacke ich eine Datei in Powershell?

224

Ich habe eine .zipDatei und muss den gesamten Inhalt mit Powershell entpacken. Ich mache das, aber es scheint nicht zu funktionieren:

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

Was ist los mit dir? Das Verzeichnis C:\aist noch leer.

Uli Kunkel
quelle
6
Wenn Sie in Powershell 2.0 oder ohne .NET 4.5 installiert sind, ist die von Ihnen erwähnte Methode der einzige Pfad (ohne eine Exe eines Drittanbieters (dh 7zip). Ich würde sagen, dass die Frage erst vollständig beantwortet wird Jemand gibt an, warum diese Methode nicht funktioniert. Sie funktioniert
manchmal

Antworten:

248

Hier ist eine einfache Möglichkeit, ExtractToDirectory aus System.IO.Compression.ZipFile zu verwenden :

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"

Beachten Sie, dass ExtractToDirectory den Zielordner erstellt, wenn er nicht vorhanden ist. Weitere Einschränkungen:

Siehe auch:

Micky Balladelli
quelle
10
Warum erstellen Sie eine Funktion, um einen einzelnen Funktionsaufruf zu ersetzen?
17
Theoretisch nicht. Ich versuche, komplexe / unkonventionelle Aufrufe in Funktionen zu verbergen, damit ich die Methode später ersetzen kann, ohne mir Gedanken darüber zu machen, wo sie verwendet wird. Wie Keith bereits erwähnt hat, wird es in V5 einen neuen Weg geben, dies zu tun.
Micky Balladelli
1
Dazu benötigen Sie mindestens .NET Framework 4.5. Siehe unten in msdn.microsoft.com/en-us/library/…
ferventcoder
10
Ich habe versucht, aber unter Fehler zu bekommen, 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
Dies gibt mir den folgenden Fehler : Add-Type : Cannot add type. The assembly 'System.IO.Compression.FileSystem' could not be found.. Ich habe .NET 4.6.2 installiert und habe überprüft, ob sich die Assembly im GAC befindet, aber ich habe nicht herausgefunden, warum ich diesen Fehler erhalte.
Sam
500

In PowerShell v5 + ist ein Befehl zum Erweitern des Archivs (sowie zum Komprimieren des Archivs) integriert:

Expand-Archive c:\a.zip -DestinationPath c:\a
Keith Hill
quelle
26
Verwenden $PSVersionTable.PSVersionSie diese Option , um zu bestimmen, welche Version von PowerShell Sie ausführen.
Brad C
1
@ LoneCoder Ich glaube nicht, dass du Ballmer die Schuld geben kannst. Windows hatte noch nie zuvor ein eingebautes Befehlszeilentool für die Verarbeitung komprimierter Dateien, obwohl gzip 1992 herauskam und tar noch älter ist.
jpmc26
2
@Ghashange PowerShell 5 war nicht einmal für etwas unter Windows 10 und Server 2012 verfügbar, als diese Antwort veröffentlicht wurde, selbst als Vorabversion.
jpmc26
11
Es sieht so aus, als ob der Parameter OutputPathin DestinationPath(Referenz msdn.microsoft.com/powershell/reference/5.1/… ) geändert wurde
Elijah W. Gagne
1
Sie können auch relative Pfade wieExpand-Archive -Path .\a.zip -DestinationPath .
Culip
24

In PowerShell v5.1 unterscheidet sich dies geringfügig von v5. Gemäß der MS-Dokumentation muss ein -PathParameter vorhanden sein, um den Pfad der Archivdatei anzugeben.

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

Oder dies kann ein tatsächlicher Weg sein:

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

Expand-Archive Doc

NIK
quelle
3
In diesem Cmdlet gibt es keinen Unterschied zwischen v5 und v5.1. Sie müssen den ersten Parameter nicht benennen. Es wird automatisch zum Pfad. Funktioniert beispielsweise Expand-Archive Draft.Zip -DestinationPath C:\Referenceohne Probleme. Außerdem ist es kein tatsächlicher Pfad, sondern ein absoluter Pfad.
Franklin Yu
13

Verwenden Sie das Expand-ArchiveCmdlet mit einem der folgenden Parametersätze:

Expand-Archive -LiteralPath C:\source\file.Zip -DestinationPath C:\destination
Expand-Archive -Path file.Zip -DestinationPath C:\destination
Saleh Rahimzadeh
quelle
12

Hey, es funktioniert für mich.

$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)
}
Abhijit
quelle
2
Wenn eine der Dateien oder Verzeichnisse bereits am Zielspeicherort vorhanden ist, wird ein Dialogfeld angezeigt, in dem Sie gefragt werden, was zu tun ist (ignorieren, überschreiben), wodurch der Zweck verfehlt wird. Weiß jemand, wie man es zwingt, stillschweigend zu überschreiben?
Oleg Kazakov
Antwort auf den Kommentar von @OlegKazakov: Es gibt eine Reihe von Optionen, die das steuern CopyHere Methode . Ich denke, @OlegKazakov hat sein Problem bereits gelöst. Trotzdem habe ich diesen Link hier für andere Surfer gesetzt, die dieses Thema finden können: docs.microsoft.com/en-us/previous-versions/windows/desktop/…
jsxt
4

Für diejenigen, die Shell.Application.Namespace.Folder.CopyHere () verwenden und Fortschrittsbalken beim Kopieren ausblenden oder weitere Optionen verwenden möchten, finden Sie hier die Dokumentation:
https://docs.microsoft.com/en-us / windows / desktop / shell / folder-copyhere

Um Powershell zu verwenden und Fortschrittsbalken auszublenden und Bestätigungen zu deaktivieren, können Sie folgenden Code verwenden:

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

Einschränkungen der Verwendung von Shell.Application unter Windows Core-Versionen:
https://docs.microsoft.com/en-us/windows-server/administration/server-core/what-is-server-core

In Windows Core- Versionen ist das Microsoft-Windows-Server-Shell-Paket standardmäßig nicht installiert, sodass shell.applicaton nicht funktioniert.

Hinweis : Das Extrahieren von Archiven auf diese Weise dauert lange und kann die Windows-Benutzeroberfläche verlangsamen

Matej Ridzon
quelle
3

Verwenden von expand-archiveVerzeichnissen, die nach dem Archiv benannt sind, aber automatisch erstellt werden:

function unzip ($file) {
    $dirname = (Get-Item $file).Basename
    New-Item -Force -ItemType directory -Path $dirname
    expand-archive $file -OutputPath $dirname -ShowProgress
}
Mikemaccana
quelle
Dies wird notwendigerweise im aktuellen Verzeichnis erweitert, nicht wahr?
jpmc26
Sehen Sie nicht wirklich den Mehrwert der automatischen Erstellung. Es ist flexibler, einen zweiten Parameter outputPathwie in der akzeptierten Antwort hinzuzufügen . In dieser Lösung (wie jpmc26 sagte) erstellen Sie immer ein neues Verzeichnis im aktuellen Verzeichnis, so dass Sie möglicherweise das aktuelle Verzeichnis festlegen müssen, bevor Sie anrufenunzip
Rubanov
Die meisten Archivierer extrahieren in ein nach dem Archiv benanntes Verzeichnis an derselben Stelle wie das Archiv. Nichts hindert Sie daran, Parameter hinzuzufügen, wenn Sie etwas anderes möchten, aber es ist eine sinnvolle Standardeinstellung.
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)
    }
}

Verwenden von:

unzip 'Applications\Site.zip' 'C:\inetpub\wwwroot\Site'
user1624251
quelle
Vergessen Sie nicht zu entsorgen $archiveund $archiveFileam Ende
tom.maruska
0

ForEachLoop verarbeitet jede ZIP-Datei innerhalb der $filepathVariablen

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