Skip to content

Instantly share code, notes, and snippets.

@bryanvine
Last active March 4, 2021 15:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bryanvine/a43fb13c8e23db6aa892a472d1d54157 to your computer and use it in GitHub Desktop.
Save bryanvine/a43fb13c8e23db6aa892a472d1d54157 to your computer and use it in GitHub Desktop.
<#
BV-ZipUtility.ps1
http://www.bryanvine.com/2017/03/powershell-script-7zipunzip-powershell.html
Author: Bryan Vine
Last updated: 03/27/2017
Description: This collection of functions can be used as a module or imported in other
modules to replace most of the functionality of 7zip.exe and unzip.exe.
#>
#Requires -version 3
Function Test-DotNet{
<#
.SYNOPSIS
Checks for a specific .NET framework
.DESCRIPTION
Uses registry keys to find all installed versions of .NET framework and check that the highest version is
greater than or equal to a minimum level. Returns true if it is, false if it isn't.
.PARAMETER MinLevel
Minimum level of .NET framework required to return true.
.EXAMPLE
Test-DotNet
This will return true if .NET 4.5 or greater is installed.
.EXAMPLE
Test-DotNet -MinLevel 4.0
This will return true if .NET 4.0 or greater is installed.
.LINK
http://www.bryanvine.com/2017/03/powershell-script-7zipunzip-powershell.html
.NOTES
Author: Bryan Vine
Last updated: 03/27/2017
#>
[cmdletbinding()]
Param(
$MinLevel = 4.5
)
((Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse |
Get-ItemProperty -name Version -ErrorAction SilentlyContinue |
Where {$_.PSChildName -match '^(?!S)\p{L}'} |
Select -ExpandProperty Version -Unique |
Sort -Descending | Select -First 1) -ge $MinLevel)
}
function Compress-toZip{
<#
.SYNOPSIS
Compresses files and folders into a zip archive.
.DESCRIPTION
Creates new a new archive or updates an existing archive from either an array of files or a directory (or array of directories).
Requires powershell v3+ and .NET 4.5 framework.
.PARAMETER Zipfile
Output name of new zip archive or existing name of archive. Full local path or UNC path prefered for best results.
.PARAMETER Source
Input File(s) or Directory/Directories which are to be compressed into the archive
.PARAMETER CompressionLevel
Amount of compression to apply. Greatest to least: 'Optimal','Fastest','NoCompression'
.PARAMETER IncludeBaseDirectory
Specifies when creating new zip archive to include the base folder when specifying an input directory.
.PARAMETER OverwriteZip
If an existing output zip archive exists, it will delete it first before creating a new one.
.EXAMPLE
Compress-toZip -Zipfile 'test.zip' -Source 'Backup'
This will create a new zip file called test.zip in the current directory with the contents of the Backup folder.
.EXAMPLE
Compress-toZip -Zipfile 'c:\temp\test.zip' -Source '\\server1\Backup'
This will create a new zip file called test.zip in c:\temp with the contents of the Backup share from Server1.
.LINK
http://www.bryanvine.com/2017/03/powershell-script-7zipunzip-powershell.html
.NOTES
Author: Bryan Vine
Last updated: 03/27/2017
#>
[cmdletbinding()]
Param(
[ValidateNotNullorEmpty()][Parameter(Position=0,Mandatory)][String]$Zipfile,
[ValidateScript({Test-Path $_})][Parameter(Position=1,Mandatory)][String[]]$Source,
[Validateset('Optimal','Fastest','NoCompression')]$CompressionLevel = 'Optimal',
[switch]$IncludeBaseDirectory,
[switch]$OverwriteZip
)
#Check for .NET 4.5+
if(!(Test-DotNet)){
Write-Error "ERROR: Unable to perform zip operation, .NET 4.5+ not detected!"
return 1
}
[Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
#Input Normalization
if($Zipfile -notlike '*.zip'){$Zipfile += '.zip'}
if($Zipfile -notlike '*\*'){$Zipfile = $pwd.Path + '\' + $Zipfile}
if($Zipfile -like '.\*'){$Zipfile = $pwd.Path + $Zipfile.Substring(1)}
#Update existing Zip
if((Test-Path $Zipfile) -and !$OverwriteZip){
Write-Verbose "Updating existing zip file"
$zip = [System.IO.Compression.ZipFile]::Open($Zipfile,"Update")
#Remove existing files which will be updated in zip
$SourceFiles = dir -Recurse $Source |?{$_.mode -notlike "d*"}| select -ExpandProperty fullname
$Overlapfiles = $SourceFiles | %{$_.replace(($Source + '\'),'')}
$duplicates = $zip.Entries | ?{$Overlapfiles -contains $_.FullName}
$duplicates | %{$_.Delete()}
$SourceFiles | %{
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($Zip, $_, ($_.replace(($Source + '\'),'')),
($CompressionLevel)) | Out-Null
}
$zip.dispose()
#New or overwrite zip completely
}else{
#Overwrite
if($OverwriteZip){Remove-Item $Zipfile -Verbose}
#Source is a directory
if(test-path $Source -PathType Container){
$Source = dir $Source | select -First 1 -ExpandProperty PSParentPath | %{$_.Replace('Microsoft.PowerShell.Core\FileSystem::','')}
[System.IO.Compression.ZipFile]::CreateFromDirectory($Source, $Zipfile,
([System.IO.Compression.CompressionLevel]::$CompressionLevel), $IncludeBaseDirectory)
#Source is a single file
}else{
$zip = [System.IO.Compression.ZipFile]::Open($Zipfile,"Update")
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($Zip, $Source, (dir $Source|select -ExpandProperty name),
($CompressionLevel))
$zip.dispose()
}
}
}
function Expand-fromZip{
<#
.SYNOPSIS
Expands files and folders from a zip archive.
.DESCRIPTION
Extracts files and folders from a zip file to a selected destination folder. UNC paths work also.
Requires powershell v3+ and .NET 4.5 framework.
.PARAMETER Zipfile
Output name of new zip archive or existing name of archive. Full local path or UNC path prefered for best results.
.PARAMETER Destination
Extration folder or path. UNC also supported. If the destination path doesn't exist, it will be created.
.EXAMPLE
Expand-fromZip -Zipfile 'test.zip' -Destination 'Restored_Backup'
This will extra the contents from test.zip into the folder Restored_Backup. If the folder doesn't exist, it will be created.
.EXAMPLE
Expand-fromZip -Zipfile 'c:\temp\test.zip' -Destination '\\server1\Backup'
This will extract the contents of the zip file called test.zip in c:\temp to the Backup share from Server1.
.LINK
http://www.bryanvine.com/2017/03/powershell-script-7zipunzip-powershell.html
.NOTES
Author: Bryan Vine
Last updated: 03/27/2017
#>
[cmdletbinding()]
Param(
[ValidateScript({Test-Path $_})][Parameter(Position=0,Mandatory)][String]$Zipfile,
[Parameter(Position=1)][String]$Destination
)
#Check for .NET 4.5+
if(!(Test-DotNet)){
Write-Error "ERROR: Unable to perform zip operation, .NET 4.5+ not detected!"
return 1
}
[Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
if(!($Destination)){
$Destination = $PWD
}
if(!(Test-Path $Destination)){
$Destination = (New-Item $Destination -ItemType Directory).FullName
}
if($Destination -notlike "*\*" -or $Destination -like ".\*"){
$Destination = dir $PWD | ?{$_.name -like $Destination -or $_.name -like $Destination.replace('.\','')} | select -ExpandProperty FullName
#select -First 1 -ExpandProperty PSParentPath | %{$_.Replace('Microsoft.PowerShell.Core\FileSystem::','')}
}
[System.IO.Compression.ZipFile]::ExtractToDirectory($Zipfile, $Destination)
}
Function Invoke-SevenZip{
<#
.SYNOPSIS
Wrapper function which calls both Compress-toZip and Expand-fromZip
.DESCRIPTION
This function effectively translates the parameters that overlap with both 7z.exe and unzip.exe.
Using the set-alias cmdlets, you can assign this function to '7z' and 'unzip' for easy substitution.
.PARAMETER CommandMode
Specifies which operation to apply. 'u' or 'a' specify compress, 'x' or 'e' specify expand.
.PARAMETER CompressionLevel
This sets the level of compression. The native .NET extensions only support 3 levels of compression.
.PARAMETER ZipFile
Specifies the zip file name to extract from or compress to.
.PARAMETER Directory
Specifies the directory (or source file) to compress from or extract to.
.PARAMETER Recurse
This switch enables recursion for compressing a target directory.
.EXAMPLE
Invoke-SevenZip a 'c:\temp\test.zip' '\\server\share\data' -m 3
This example compresses the contents of the data folder on server using the highest compression into the test.zip file locally.
.EXAMPLE
Invoke-SevenZip x 'c:\temp\test.zip' '.\bob'
This extracts the contents of test.zip into a folder named bob in the current directory.
.LINK
http://www.bryanvine.com/2017/03/powershell-script-7zipunzip-powershell.html
.LINK
Compress-toZip
.LINK
Expand-fromZip
.NOTES
Author: Bryan Vine
Last updated: 03/27/2017
#>
[cmdletbinding()]
Param(
[Validateset('a','e','u','x')][Parameter(Position=0,Mandatory)][String]$CommandMode,
[Parameter(Position=1,Mandatory)][String]$ZipFile,
[Parameter(Position=2)][String[]]$Directory,
[Validateset('5','4','3','2','1','0','Optimal','Fastest','NoCompression')][Alias("m")]$CompressionLevel = 'Optimal',
[Alias("r")][Switch]$Recurse
)
switch($CompressionLevel){
"5" {$CompressionLevel = 'Optimal'}
"4" {$CompressionLevel = 'Optimal'}
"3" {$CompressionLevel = 'Optimal'}
"2" {$CompressionLevel = 'Optimal'}
"1" {$CompressionLevel = 'Fastest'}
"0" {$CompressionLevel = 'NoCompression'}
}
if(!($Directory)){
$Directory = $PWD
}
if($CommandMode -like 'u' -or $CommandMode -like 'a'){
Compress-toZip -Zipfile $ZipFile -Source $Directory -CompressionLevel $CompressionLevel
}
if($CommandMode -like 'e' -or $CommandMode -like 'x'){
Expand-fromZip -Zipfile $ZipFile -Destination $Directory
}
}
Set-Alias -Name '7z' -Value 'Invoke-SevenZip'
Set-Alias -Name 'Unzip' -Value 'Invoke-SevenZip'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment