27
Add-Type -A System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::CreateFromDirectory('foo', 'foo.zip')
[IO.Compression.ZipFile]::ExtractToDirectory('foo.zip', 'bar')

I found the code to create and extract .zip files via PowerShell from this answer, but because of my low reputation I cannot ask a question as a comment on that answer.

  • Creating - How to overwrite an existing .zip file without user interaction?
  • Extracting - How to overwrite existing files and folders without user interaction? (Preferably like robocopys mir function).
henrycarteruk
  • 12,708
  • 2
  • 36
  • 40
Clacers
  • 401
  • 2
  • 6
  • 12
  • What does the [documentation](https://msdn.microsoft.com/en-us/library/system.io.compression.zipfile(v=vs.110).aspx) tell you? – Ken White Aug 10 '17 at 16:17
  • Which version of PowerShell are you using? [`Compress-Archive`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Archive/Compress-Archive?view=powershell-5.1) is a better option if you are on `5.0` or higher. – G42 Aug 10 '17 at 16:20

2 Answers2

45

PowerShell has built-in .zip utilities without needing to use .NET class methods in version 5 and above. The Compress-Archive -Path argument also takes a string[] type so you can zip multiple folders/files into the destination zip.


Zipping:

Compress-Archive -Path C:\Foo -DestinationPath C:\Foo.zip -CompressionLevel Optimal -Force

There is also an -Update switch.

Unzipping:

Expand-Archive -Path C:\Foo.zip -DestinationPath C:\Foo -Force
Maximilian Burszley
  • 18,243
  • 4
  • 34
  • 63
9

PowerShell versions prior to 5 can execute this script

Thanks to @Ola-M for update.

Thanks to @maximilian-burszley for update.

function Unzip($zipfile, $outdir)
{
    Add-Type -AssemblyName System.IO.Compression.FileSystem
    $archive = [System.IO.Compression.ZipFile]::OpenRead($zipfile)
    try
    {
        foreach ($entry in $archive.Entries)
        {
            $entryTargetFilePath = [System.IO.Path]::Combine($outdir, $entry.FullName)
            $entryDir = [System.IO.Path]::GetDirectoryName($entryTargetFilePath)

            #Ensure the directory of the archive entry exists
            if(!(Test-Path $entryDir )){
                New-Item -ItemType Directory -Path $entryDir | Out-Null 
            }

            #If the entry is not a directory entry, then extract entry
            if(!$entryTargetFilePath.EndsWith("\")){
                [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $entryTargetFilePath, $true);
            }
        }
    }
    finally
    {
        $archive.Dispose()
    }
}

Unzip -zipfile "$zip" -outdir "$dir"
yW0K5o
  • 913
  • 1
  • 17
  • 32
  • Some resources are not released, as I'm getting "Copy-Item : The process cannot access the file 'my.zip' because it is being used by another process." – Ola M Jul 30 '19 at 21:05
  • 1
    I've added a line to fix it ($archive.Dispose()) – Ola M Jul 30 '19 at 21:10
  • 1
    A suggestion: wrap in a try/finally with disposal of managed resources happening in finally so even if something is SIGINTed, they're released. – Maximilian Burszley Jul 15 '20 at 19:43