¿Cómo descomprimir un archivo en Powershell?

224

Tengo un .ziparchivo y necesito descomprimir todo su contenido usando Powershell. Estoy haciendo esto pero no parece funcionar:

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

Que pasa El directorio C:\aaún está vacío.

Uli Kunkel
fuente
66
Si está en Powershell 2.0, o sin .NET 4.5 instalado, entonces el método que mencionó es la única ruta (sin ir con un exe de terceros (es decir, 7zip). Diría que la pregunta no se responde completamente hasta alguien ofrece por qué este método no funciona para mí lo hace parte del tiempo, pero otros no lo hace..
Kenny

Respuestas:

248

Aquí hay una manera simple de usar 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"

Tenga en cuenta que si la carpeta de destino no existe, ExtractToDirectory la creará. Otras advertencias:

  • Los archivos existentes no se sobrescribirán y en su lugar desencadenarán una IOException.
  • Este método requiere al menos .NET Framework 4.5, disponible para Windows Vista y versiones posteriores.
  • Las rutas relativas no se resuelven según el directorio de trabajo actual. Consulte ¿Por qué los objetos .NET en PowerShell no usan el directorio actual?

Ver también:

Micky Balladelli
fuente
10
¿Por qué crea una función para reemplazar una sola llamada de función?
17
En teoría no lo haces. Intento ocultar llamadas complejas / no convencionales en funciones para luego poder reemplazar el método sin preocuparme de dónde se usa. Como mencionó Keith, en V5 habrá una nueva forma de hacerlo.
Micky Balladelli
1
Necesita al menos .NET Framework 4.5 para esto. Vea la parte inferior de msdn.microsoft.com/en-us/library/…
ferventcoder
10
Intenté esto pero 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
obtengo el
44
Esto me da el error siguiente: Add-Type : Cannot add type. The assembly 'System.IO.Compression.FileSystem' could not be found.. Tengo instalado .NET 4.6.2 y he verificado que el ensamblado está en el GAC, pero no descubrí por qué recibo este error.
Sam
500

En PowerShell v5 +, hay un comando Expandir-Archivo (así como también Compress-Archive) integrado:

Expand-Archive c:\a.zip -DestinationPath c:\a
Keith Hill
fuente
26
Use $PSVersionTable.PSVersionpara determinar qué versión de PowerShell está ejecutando.
Brad C
1
@LoneCoder No creo que puedas culpar a Ballmer. Windows nunca antes había tenido una herramienta de línea de comandos integrada para manejar archivos comprimidos, a pesar de que gzip salió en 1992 y el tar es aún más antiguo.
jpmc26
2
@Ghashange PowerShell 5 ni siquiera estaba disponible para nada por debajo de Windows 10 y Server 2012 cuando se publicó esta respuesta, incluso como versión preliminar.
jpmc26
11
Parece que el parámetro OutputPathha sido cambiado a DestinationPath(referencia msdn.microsoft.com/powershell/reference/5.1/… )
Elijah W. Gagne el
1
También puede usar rutas relativas comoExpand-Archive -Path .\a.zip -DestinationPath .
Culip
24

En PowerShell v5.1 esto es ligeramente diferente en comparación con v5. De acuerdo con la documentación de MS, debe tener un -Pathparámetro para especificar la ruta del archivo comprimido.

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

O bien, esto puede ser un camino real:

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

Expandir-Archivar documento

NIK
fuente
3
No hay diferencia entre v5 y v5.1 en este Cmdlet. No necesita nombrar el primer parámetro; se convertirá automáticamente en el camino. Por ejemplo, Expand-Archive Draft.Zip -DestinationPath C:\Referencefunciona sin problemas. Además, no es la ruta real , sino la ruta absoluta .
Franklin Yu
13

Use Expand-Archivecmdlet con uno de conjunto de parámetros:

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

Hola, está funcionando para mí ...

$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
fuente
2
Si uno de los archivos o directorios ya existe en la ubicación de destino, aparece un cuadro de diálogo preguntando qué hacer (ignorar, sobrescribir) que anula el propósito. ¿Alguien sabe cómo forzarlo a sobrescribir en silencio?
Oleg Kazakov
Respondiendo al comentario de @OlegKazakov: hay un conjunto de opciones que controlan el CopyHeremétodo. Supongo que @OlegKazakov ya resolvió su problema. Sin embargo, pongo este enlace aquí para otros surfistas que pueden encontrar este tema: docs.microsoft.com/en-us/previous-versions/windows/desktop/…
jsxt
4

Para aquellos que desean usar Shell.Application.Namespace.Folder.CopyHere () y quieren ocultar las barras de progreso mientras copian, o usar más opciones, la documentación está aquí:
https://docs.microsoft.com/en-us / windows / desktop / shell / folder-copyhere

Para usar powershell y ocultar barras de progreso e inhabilitar confirmaciones, puede usar un código como este:

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

Limitaciones de uso de Shell. Aplicación en versiones principales de Windows:
https://docs.microsoft.com/en-us/windows-server/administration/server-core/what-is-server-core

En las versiones principales de Windows , de forma predeterminada, Microsoft-Windows-Server-Shell-Package no está instalado, por lo que shell.applicaton no funcionará.

nota : la extracción de archivos de esta manera llevará mucho tiempo y puede ralentizar la interfaz gráfica de usuario de Windows

Matej Ridzon
fuente
3

Utilizando expand-archivedirectorios de creación automática pero con el nombre del archivo:

function unzip ($file) {
    $dirname = (Get-Item $file).Basename
    New-Item -Force -ItemType directory -Path $dirname
    expand-archive $file -OutputPath $dirname -ShowProgress
}
mikemaccana
fuente
Esto necesariamente se expande en el directorio actual, ¿no?
jpmc26
Realmente no veo el valor agregado de la creación automática. Es más flexible agregar un segundo parámetro outputPathcomo en la respuesta aceptada. En esta solución (como dijo jpmc26), siempre creará un nuevo directorio en el directorio actual, por lo que es posible que necesite configurar el directorio actual antes de llamarunzip
Rubanov
La mayoría de los archivadores extraen en un directorio con el nombre del archivo, en el mismo lugar que el archivo. No hay nada que te impida agregar parámetros si quieres algo diferente, pero es un valor predeterminado razonable.
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)
    }
}

Utilizando:

unzip 'Applications\Site.zip' 'C:\inetpub\wwwroot\Site'
usuario1624251
fuente
No te olvides de deshacerte $archivey $archiveFileal final
tom.maruska
0

ForEachLoop procesa cada archivo ZIP ubicado dentro de 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
fuente