PoshCode Logo PowerShell Code Repository

ZipFile Module by Simon64 10 months ago (modification of post by Joel Bennett view diff)
diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/4845"></script>download | new post

New-ZipFile and Expand-ZipFile — two functions for zipping and unzipping the way I like doing it…

  1. Add-Type -As System.IO.Compression.FileSystem
  2.  
  3. function New-ZipFile {
  4.   #.Synopsis
  5.   #  Create a new zip file, optionally appending to an existing zip...
  6.   [CmdletBinding()]
  7.   param(
  8.     # The path of the zip to create
  9.     [Parameter(Position=0, Mandatory=$true)]
  10.     $ZipFilePath,
  11.  
  12.     # Items that we want to add to the ZipFile
  13.     [Parameter(Position=1, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
  14.     [Alias("PSPath","Item")]
  15.     [string[]]$InputObject = $Pwd,
  16.  
  17.     # Append to an existing zip file, instead of overwriting it
  18.     [Switch]$Append,
  19.  
  20.     # The compression level (defaults to Optimal):
  21.     #   Optimal - The compression operation should be optimally compressed, even if the operation takes a longer time to complete.
  22.     #   Fastest - The compression operation should complete as quickly as possible, even if the resulting file is not optimally compressed.
  23.     #   NoCompression - No compression should be performed on the file.
  24.     [System.IO.Compression.CompressionLevel]$Compression = "Optimal"
  25.   )
  26.   begin {
  27.     # Make sure the folder already exists
  28.     [string]$File = Split-Path $ZipFilePath -Leaf
  29.     [string]$Folder = $(if($Folder = Split-Path $ZipFilePath) { Resolve-Path $Folder } else { $Pwd })
  30.     $ZipFilePath = Join-Path $Folder $File
  31.     # If they don't want to append, make sure the zip file doesn't already exist.
  32.     if(!$Append) {
  33.       if(Test-Path $ZipFilePath) { Remove-Item $ZipFilePath }
  34.     }
  35.     $Archive = [System.IO.Compression.ZipFile]::Open( $ZipFilePath, "Update" )
  36.   }
  37.   process {
  38.     foreach($path in $InputObject) {
  39.       foreach($item in Resolve-Path $path) {
  40.         # Push-Location so we can use Resolve-Path -Relative
  41.         Push-Location (Split-Path $item)
  42.         # This will get the file, or all the files in the folder (recursively)
  43.         foreach($file in Get-ChildItem $item -Recurse -File -Force | % FullName) {
  44.           # Calculate the relative file path
  45.           $relative = (Resolve-Path $file -Relative).TrimStart(".\")
  46.           # Add the file to the zip
  47.           $null = [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($Archive, $file, $relative, $Compression)
  48.         }
  49.         Pop-Location
  50.       }
  51.     }
  52.   }
  53.   end {
  54.     $Archive.Dispose()
  55.     Get-Item $ZipFilePath
  56.   }
  57. }
  58.  
  59.  
  60. function Expand-ZipFile {
  61.   #.Synopsis
  62.   #  Expand a zip file, ensuring it's contents go to a single folder ...
  63.   [CmdletBinding()]
  64.   param(
  65.     # The path of the zip file that needs to be extracted
  66.     [Parameter(ValueFromPipelineByPropertyName=$true, Position=0, Mandatory=$true)]
  67.     [Alias("PSPath")]
  68.     $FilePath,
  69.  
  70.     # The path where we want the output folder to end up
  71.     [Parameter(Position=1)]
  72.     $OutputPath = $Pwd,
  73.  
  74.     # Make sure the resulting folder is always named the same as the archive
  75.     [Switch]$Force
  76.   )
  77.   process {
  78.     $ZipFile = Get-Item $FilePath
  79.     $Archive = [System.IO.Compression.ZipFile]::Open( $ZipFile, "Read" )
  80.  
  81.     # Figure out where we'd prefer to end up
  82.     if(Test-Path $OutputPath) {
  83.       # If they pass a path that exists, we want to create a new folder
  84.       $Destination = Join-Path $OutputPath $ZipFile.BaseName
  85.     } else {
  86.       # Otherwise, since they passed a folder, they must want us to use it
  87.       $Destination = $OutputPath
  88.     }
  89.  
  90.     # The root folder of the first entry ...
  91.     $ArchiveRoot = ($Archive.Entries[0].FullName -Split "/|\\")[0]
  92.  
  93.     Write-Verbose "Desired Destination: $Destination"
  94.     Write-Verbose "Archive Root: $ArchiveRoot"
  95.  
  96.     # If any of the files are not in the same root folder ...
  97.     if($Archive.Entries.FullName | Where-Object { @($_ -Split "/|\\")[0] -ne $ArchiveRoot }) {
  98.       # extract it into a new folder:
  99.       New-Item $Destination -Type Directory -Force
  100.       [System.IO.Compression.ZipFileExtensions]::ExtractToDirectory( $Archive, $Destination )
  101.     } else {
  102.       # otherwise, extract it to the OutputPath
  103.       [System.IO.Compression.ZipFileExtensions]::ExtractToDirectory( $Archive, $OutputPath )
  104.  
  105.       # If there was only a single file in the archive, then we'll just output that file...
  106.       if($Archive.Entries.Count -eq 1) {
  107.         # Except, if they asked for an OutputPath with an extension on it, we'll rename the file to that ...
  108.         if([System.IO.Path]::GetExtension($Destination)) {
  109.           Move-Item (Join-Path $OutputPath $Archive.Entries[0].FullName) $Destination
  110.         } else {
  111.           Get-Item (Join-Path $OutputPath $Archive.Entries[0].FullName)
  112.         }
  113.       } elseif($Force) {
  114.         # Otherwise let's make sure that we move it to where we expect it to go, in case the zip's been renamed
  115.         if($ArchiveRoot -ne $ZipFile.BaseName) {
  116.           Move-Item (join-path $OutputPath $ArchiveRoot) $Destination
  117.           Get-Item $Destination
  118.         }
  119.       } else {
  120.         Get-Item (Join-Path $OutputPath $ArchiveRoot)
  121.       }
  122.     }
  123.  
  124.     $Archive.Dispose()
  125.   }
  126. }

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me