Powershell script to extract a zip file recursively

4 Sep 2016

I have been explore a few different way. There are a few things to mention:

  1. Using shell.application with CopyHere doesn't work well because sometimes a directory entry is not in the zip file. Therefore, CopyHere($path) fails when $path's parent doesn't exist.
  2. $ErrorActionPreference = "Stop" is absolutely necessary. It means the script stops if there's any error. The default value is “Continue”.
  3. New-Item -ItemType Directory -Path $fullPath creates the directory along with all of its parent. It works like mkdir -p.
  4. There's no other way to check if ZipArchiveEntry is a directory. The only way to check it is to check the trailing / or \.
  5. As you will see, the script works with extract a zip into an existing folder as well.

Here's the full script:

# Exit if any command/function sees an error $ErrorActionPreference = "Stop" function Create-Dir-If-Not-Exist($fullPath) { if (!(Test-Path $fullPath)) { Write-Host "Create dir: $fullPath" New-Item -ItemType Directory -Path $fullPath | Out-Null } } function Unzip($zipfile, $outdir) { Add-Type -AssemblyName System.IO.Compression.FileSystem $zip = [System.IO.Compression.ZipFile]::OpenRead($zipfile) foreach ($entry in $zip.Entries) { $destFilePath = [System.IO.Path]::Combine($outdir, $entry.FullName) $isDir = ($destFilePath.EndsWith("\") -or $destFilePath.EndsWith("/")) if ($isDir) { Create-Dir-If-Not-Exist($destFilePath) } else { $parentDir = [System.IO.Path]::GetDirectoryName($destFilePath) # Sometimes its parent directory is not an entry in $zip. # Therefore, we need to make sure its parent dir exists. # Also, Create-Dir-If-Not-Exist(..) is an equivalent of `mkdir -p`. # Therefore, we don't need to worry about the parent's parent. Create-Dir-If-Not-Exist($parentDir) Write-Host "Extract: $destFilePath" [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $destFilePath, $true) | Out-Null } } } $zip_file_path = [IO.Path]::GetFullPath("c:\Users\tanin\test.zip") $dest_path = [IO.Path]::GetFullPath("c:\Users\tanin\extracted_test") Unzip $zip_file_path $dest_path