Comment décompresser un fichier dans Powershell?

224

J'ai un .zipfichier et j'ai besoin de décompresser tout son contenu à l'aide de Powershell. Je fais ça mais ça ne semble pas fonctionner:

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

Qu'est-ce qui ne va pas? Le répertoire C:\aest toujours vide.

Uli Kunkel
la source
6
Si vous êtes dans Powershell 2.0, ou sans .NET 4.5 installé, alors la méthode que vous avez mentionnée est le seul chemin (sans aller avec un exe tiers (c'est-à-dire 7zip). Je dirais que la question n'est pas entièrement répondue jusqu'à ce que quelqu'un explique pourquoi cette méthode ne fonctionne pas. Elle le fait pour moi une partie du temps, mais d'autres non.
kenny

Réponses:

248

Voici un moyen simple d'utiliser ExtractToDirectory de 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"

Notez que si le dossier cible n'existe pas, ExtractToDirectory le créera. Autres mises en garde:

Voir également:

Micky Balladelli
la source
10
Pourquoi créez-vous une fonction pour remplacer un seul appel de fonction?
17
En théorie, non. J'essaie de cacher les appels complexes / non conventionnels dans les fonctions afin que plus tard je puisse remplacer la méthode sans se soucier de l'endroit où elle est utilisée. Comme Keith l'a mentionné, dans V5, il y aura une nouvelle façon de le faire.
Micky Balladelli du
1
Pour cela, vous avez besoin d'au moins .NET Framework 4.5. Voir le bas de msdn.microsoft.com/en-us/library/…
ferventcoder
10
J'ai essayé cela, mais en dessous de l'erreur, 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
Cela me donne l'erreur suivante: Add-Type : Cannot add type. The assembly 'System.IO.Compression.FileSystem' could not be found.. J'ai .NET 4.6.2 installé et j'ai vérifié que l'assembly est dans le GAC, mais je n'ai pas compris pourquoi j'obtiens cette erreur.
Sam
500

Dans PowerShell v5 +, il existe une commande Expand-Archive (ainsi que Compress-Archive) intégrée dans:

Expand-Archive c:\a.zip -DestinationPath c:\a
Keith Hill
la source
26
Utilisez $PSVersionTable.PSVersionpour déterminer la version de PowerShell que vous exécutez.
Brad C
1
@LoneCoder Je ne pense pas que vous puissiez blâmer Ballmer. Windows n'a jamais eu auparavant d'outil de ligne de commande intégré pour gérer les fichiers compressés, même si gzip est sorti en 1992 et que tar est encore plus ancien.
jpmc26
2
@Ghashange PowerShell 5 n'était même pas disponible pour tout ce qui est inférieur à Windows 10 et Server 2012 lorsque cette réponse a été publiée, même en version préliminaire.
jpmc26
11
On dirait que le paramètre OutputPatha été changé en DestinationPath(référence msdn.microsoft.com/powershell/reference/5.1/… )
Elijah W. Gagne
1
Vous pouvez également utiliser des chemins relatifs commeExpand-Archive -Path .\a.zip -DestinationPath .
Culip
24

Dans PowerShell v5.1, cela est légèrement différent de v5. Selon la documentation MS, il doit avoir un -Pathparamètre pour spécifier le chemin du fichier d'archive.

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

Ou bien, cela peut être un chemin réel:

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

Expand-Archive Doc

NIK
la source
3
Il n'y a aucune différence entre la v5 et la v5.1 dans cette applet de commande. Vous n'avez pas besoin de nommer le premier paramètre; il deviendra automatiquement le chemin. Par exemple, Expand-Archive Draft.Zip -DestinationPath C:\Referencefonctionne sans problème. De plus, ce n'est pas un chemin réel , mais un chemin absolu .
Franklin Yu
13

Utilisez l' Expand-Archiveapplet de commande avec l'un des jeux de paramètres:

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

Hey ça marche pour moi ..

$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
la source
2
Si l'un des fichiers ou répertoires existe déjà à l'emplacement de destination, il ouvre une boîte de dialogue vous demandant quoi faire (ignorer, écraser) qui va à l'encontre de l'objectif. Est-ce que quelqu'un sait comment le forcer à écraser silencieusement?
Oleg Kazakov
Réponse au commentaire de @OlegKazakov: il existe un ensemble d'options contrôlant la CopyHereméthode. Je suppose que @OlegKazakov a déjà résolu son problème. Néanmoins, je mets ce lien ici pour les autres surfeurs qui peuvent trouver ce sujet: docs.microsoft.com/en-us/previous-versions/windows/desktop/…
jsxt
4

Pour ceux qui souhaitent utiliser Shell.Application.Namespace.Folder.CopyHere () et veulent masquer les barres de progression lors de la copie, ou utiliser plus d'options, la documentation est ici:
https://docs.microsoft.com/en-us / windows / desktop / shell / folder-copyhere

Pour utiliser PowerShell et masquer les barres de progression et désactiver les confirmations, vous pouvez utiliser un code comme celui-ci:

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

Limitations d'utilisation de Shell.Application sur les versions de base de Windows:
https://docs.microsoft.com/en-us/windows-server/administration/server-core/what-is-server-core

Sur les versions de base de Windows , par défaut, Microsoft-Windows-Server-Shell-Package n'est pas installé, donc shell.applicaton ne fonctionnera pas.

Remarque : l'extraction des archives de cette manière prendra beaucoup de temps et peut ralentir l'interface graphique de Windows.

Matej Ridzon
la source
3

Utilisation expand-archivemais création automatique de répertoires nommés d'après l'archive:

function unzip ($file) {
    $dirname = (Get-Item $file).Basename
    New-Item -Force -ItemType directory -Path $dirname
    expand-archive $file -OutputPath $dirname -ShowProgress
}
mikemaccana
la source
Cela se développe nécessairement dans le répertoire courant, n'est-ce pas?
jpmc26
Ne voyez pas vraiment la valeur ajoutée de la création automatique. Il est plus flexible d'ajouter un deuxième paramètre outputPathcomme dans la réponse acceptée. Dans cette solution (comme l'a dit jpmc26), vous créerez toujours un nouveau répertoire dans le répertoire actuel, il est donc possible que vous deviez définir le répertoire actuel avant d'appelerunzip
Rubanov
La plupart des archiveurs extraient dans un répertoire nommé d'après l'archive, au même endroit que l'archive. Rien ne vous empêche d'ajouter des paramètres si vous voulez quelque chose de différent, mais c'est un défaut raisonnable.
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)
    }
}

En utilisant:

unzip 'Applications\Site.zip' 'C:\inetpub\wwwroot\Site'
user1624251
la source
N'oubliez pas de disposer $archiveet $archiveFileà la fin
tom.maruska
0

ForEachLa boucle traite chaque fichier ZIP situé dans la $filepathvariable

    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
la source