Is it possible to create a zip archive using PowerShell?
问题:
回答1:
If you head on over to CodePlex and grab the PowerShell Community Extensions, you can use their write-zip
cmdlet.
Since
CodePlex is in read-only mode in preparation for shutdown
you can go to PowerShell Gallery.
回答2:
A pure PowerShell alternative that works with PowerShell 3 and .NET 4.5 (if you can use it):
function ZipFiles( $zipfilename, $sourcedir )
{
Add-Type -Assembly System.IO.Compression.FileSystem
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
[System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir,
$zipfilename, $compressionLevel, $false)
}
Just pass in the full path to the zip archive you would like to create and the full path to the directory containing the files you would like to zip.
回答3:
PowerShell v5.0 adds Compress-Archive
and Expand-Archive
cmdlets. The linked pages have full examples, but the gist of it is:
# Create a zip file with the contents of C:\\Stuff\\
Compress-Archive -Path C:\\Stuff -DestinationPath archive.zip
# Add more files to the zip file
# (Existing files in the zip file with the same name are replaced)
Compress-Archive -Path C:\\OtherStuff\\*.txt -Update -DestinationPath archive.zip
# Extract the zip file to C:\\Destination\\
Expand-Archive -Path archive.zip -DestinationPath C:\\Destination
回答4:
A native way with latest .NET 4.5 framework, but entirely feature-less:
Creation:
Add-Type -Assembly \"System.IO.Compression.FileSystem\" ;
[System.IO.Compression.ZipFile]::CreateFromDirectory(\"c:\\your\\directory\\to\\compress\", \"yourfile.zip\") ;
Extraction:
Add-Type -Assembly \"System.IO.Compression.FileSystem\" ;
[System.IO.Compression.ZipFile]::ExtractToDirectory(\"yourfile.zip\", \"c:\\your\\destination\") ;
As mentioned, totally feature-less, so don\'t expect an overwrite flag.
UPDATE: See below for other developers that have expanded on this over the years...
回答5:
Install 7zip (or download the command line version instead) and use this PowerShell method:
function create-7zip([String] $aDirectory, [String] $aZipfile){
[string]$pathToZipExe = \"$($Env:ProgramFiles)\\7-Zip\\7z.exe\";
[Array]$arguments = \"a\", \"-tzip\", \"$aZipfile\", \"$aDirectory\", \"-r\";
& $pathToZipExe $arguments;
}
You can the call it like this:
create-7zip \"c:\\temp\\myFolder\" \"c:\\temp\\myFolder.zip\"
回答6:
Edit two - This code is an ugly, ugly kluge from olden days. You do not want it.
This compresses the contents of .\\in
to .\\out.zip
with System.IO.Packaging.ZipPackage following the example here
$zipArchive = $pwd.path + \"\\out.zip\"
[System.Reflection.Assembly]::Load(\"WindowsBase,Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\")
$ZipPackage=[System.IO.Packaging.ZipPackage]::Open($zipArchive,
[System.IO.FileMode]\"OpenOrCreate\", [System.IO.FileAccess]\"ReadWrite\")
$in = gci .\\in | select -expand fullName
[array]$files = $in -replace \"C:\",\"\" -replace \"\\\\\",\"/\"
ForEach ($file In $files)
{
$partName=New-Object System.Uri($file, [System.UriKind]\"Relative\")
$part=$ZipPackage.CreatePart($partName, \"application/zip\",
[System.IO.Packaging.CompressionOption]\"Maximum\")
$bytes=[System.IO.File]::ReadAllBytes($file)
$stream=$part.GetStream()
$stream.Write($bytes, 0, $bytes.Length)
$stream.Close()
}
$ZipPackage.Close()
Edit: Unreliable for larger files, maybe >10mb, YMMV. Something to do with appdomain evidence and isolated storage. The friendlier .NET 4.5 approach works nicely from PS v3, but wanted more memory in my case. To use .NET 4 from PS v2, config files need an unsupported tweak.
回答7:
Giving below another option. This will zip up a full folder and will write the archive to a given path with the given name.
Requires .NET 3 or above
Add-Type -assembly \"system.io.compression.filesystem\"
$source = \'Source path here\'
$destination = \"c:\\output\\dummy.zip\"
If(Test-path $destination) {Remove-item $destination}
[io.compression.zipfile]::CreateFromDirectory($Source, $destination)
回答8:
For compression, I would use a library (7-Zip is good like Michal suggests).
If you install 7-Zip, the installed directory will contain 7z.exe
which is a console application.
You can invoke it directly and use any compression option you want.
If you wish to engage with the DLL, that should also be possible.
7-Zip is freeware and open source.
回答9:
What about System.IO.Packaging.ZipPackage
?
It would require .NET 3.0 or greater.
#Load some assemblys. (No line break!)
[System.Reflection.Assembly]::Load(\"WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\")
#Create a zip file named \"MyZipFile.zip\". (No line break!)
$ZipPackage=[System.IO.Packaging.ZipPackage]::Open(\"C:\\MyZipFile.zip\",
[System.IO.FileMode]\"OpenOrCreate\", [System.IO.FileAccess]\"ReadWrite\")
#The files I want to add to my archive:
$files = @(\"/Penguins.jpg\", \"/Lighthouse.jpg\")
#For each file you want to add, we must extract the bytes
#and add them to a part of the zip file.
ForEach ($file In $files)
{
$partName=New-Object System.Uri($file, [System.UriKind]\"Relative\")
#Create each part. (No line break!)
$part=$ZipPackage.CreatePart($partName, \"\",
[System.IO.Packaging.CompressionOption]\"Maximum\")
$bytes=[System.IO.File]::ReadAllBytes($file)
$stream=$part.GetStream()
$stream.Write($bytes, 0, $bytes.Length)
$stream.Close()
}
#Close the package when we\'re done.
$ZipPackage.Close()
via Anders Hesselbom
回答10:
This is really obscure but works. 7za.exe is standalone version of 7zip and is available with install package.
# get files to be send
$logFiles = Get-ChildItem C:\\Logging\\*.* -Include *.log | where {$_.Name -match $yesterday}
foreach ($logFile in $logFiles)
{
Write-Host (\"Processing \" + $logFile.FullName)
# compress file
& ./7za.exe a -mmt=off ($logFile.FullName + \".7z\") $logFile.FullName
}
回答11:
function Zip-File
{
param (
[string]$ZipName,
[string]$SourceDirectory
)
Add-Type -Assembly System.IO.Compression.FileSystem
$Compress = [System.IO.Compression.CompressionLevel]::Optimal
[System.IO.Compression.ZipFile]::CreateFromDirectory($SourceDirectory,
$ZipName, $Compress, $false)
}
Note:
ZipName: Full Path of the Zip File which you want to create.
SourceDirectory: Full path to the directory containing the files which you would like to zip.
回答12:
here is a native solution for ps v5, using cmdlet Compress-Archive
Creating Zip files using PowerShell
回答13:
Why does no one look at the documentation?? There\'s a supported method of creating an empty zip file and adding individual files to it built into the same .NET 4.5 library everyone is referencing.
See below for a code example:
# Load the .NET assembly
Add-Type -Assembly \'System.IO.Compression.FileSystem\'
# Must be used for relative file locations with .NET functions instead of Set-Location:
[System.IO.Directory]::SetCurrentDirectory(\'.\\Desktop\')
# Create the zip file and open it:
$z = [System.IO.Compression.ZipFile]::Open(\'z.zip\', [System.IO.Compression.ZipArchiveMode]::Create)
# Add a compressed file to the zip file:
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($z, \'t.txt\', \'t.txt\')
# Close the file
$z.Dispose()
I encourage you to browse the documentation if you have any questions.
回答14:
If someone needs to zip a single file (and not a folder): http://blogs.msdn.com/b/jerrydixon/archive/2014/08/08/zipping-a-single-file-with-powershell.aspx
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[ValidateScript({Test-Path -Path $_ -PathType Leaf})]
[string]$sourceFile,
[Parameter(Mandatory=$True)]
[ValidateScript({-not(Test-Path -Path $_ -PathType Leaf)})]
[string]$destinationFile
)
<#
.SYNOPSIS
Creates a ZIP file that contains the specified innput file.
.EXAMPLE
FileZipper -sourceFile c:\\test\\inputfile.txt
-destinationFile c:\\test\\outputFile.zip
#>
function New-Zip
{
param([string]$zipfilename)
set-content $zipfilename
(\"PK\" + [char]5 + [char]6 + (\"$([char]0)\" * 18))
(dir $zipfilename).IsReadOnly = $false
}
function Add-Zip
{
param([string]$zipfilename)
if(-not (test-path($zipfilename)))
{
set-content $zipfilename
(\"PK\" + [char]5 + [char]6 + (\"$([char]0)\" * 18))
(dir $zipfilename).IsReadOnly = $false
}
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipfilename)
foreach($file in $input)
{
$zipPackage.CopyHere($file.FullName)
Start-sleep -milliseconds 500
}
}
dir $sourceFile | Add-Zip $destinationFile
回答15:
Here is a slightly improved version of sonjz\'s answer,it adds an overwrite option.
function Zip-Files(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$false)]
[string] $zipfilename,
[Parameter(Position=1, Mandatory=$true, ValueFromPipeline=$false)]
[string] $sourcedir,
[Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$false)]
[bool] $overwrite)
{
Add-Type -Assembly System.IO.Compression.FileSystem
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
if ($overwrite -eq $true )
{
if (Test-Path $zipfilename)
{
Remove-Item $zipfilename
}
}
[System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir, $zipfilename, $compressionLevel, $false)
}
回答16:
Here is the working code, zipping all files from a source folder and create a zip file in destination folder.
$DestZip=\"C:\\Destination\\\"
$Source = \"C:\\Source\\\"
$folder = Get-Item -Path $Source
$ZipTimestamp = Get-Date -format yyyyMMdd-HHmmss;
$ZipFileName = $DestZip + \"Backup_\" + $folder.name + \"_\" + $ZipTimestamp + \".zip\"
$Source
set-content $ZipFileName (\"PK\" + [char]5 + [char]6 + (\"$([char]0)\" * 18))
# Wait for the zip file to be created.
while (!(Test-Path -PathType leaf -Path $ZipFileName))
{
Start-Sleep -Milliseconds 20
}
$ZipFile = (new-object -com shell.application).NameSpace($ZipFileName)
Write-Output (\">> Waiting Compression : \" + $ZipFileName)
#BACKUP - COPY
$ZipFile.CopyHere($Source)
$ZipFileName
# ARCHIVE
Read-Host \"Please Enter..\"
回答17:
This should also work for compressing a single file without using a temp folder and using native .Net 4.5, converted from C# from this StackOverflow answer. It uses a nicer using syntax taken from here.
Usage:
ZipFiles -zipFilename output.zip -sourceFile input.sql -filename name.inside.zip.sql
Code:
function ZipFiles([string] $zipFilename, [string] $sourceFile, [string] $filename)
{
$fullSourceFile = (Get-Item -Path \"$sourceFile\" -Verbose).FullName
$fullZipFile = (Get-Item -Path \"$zipFilename\" -Verbose).FullName
Add-Type -AssemblyName System.IO
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
Using-Object ($fs = New-Object System.IO.FileStream($fullZipFile, [System.IO.FileMode]::Create)) {
Using-Object ($arch = New-Object System.IO.Compression.ZipArchive($fs, [System.IO.Compression.ZipArchiveMode]::Create)) {
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($arch, $fullSourceFile, $filename)
}
}
}
Using:
function Using-Object
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[AllowEmptyString()]
[AllowEmptyCollection()]
[AllowNull()]
[Object]
$InputObject,
[Parameter(Mandatory = $true)]
[scriptblock]
$ScriptBlock
)
try
{
. $ScriptBlock
}
finally
{
if ($null -ne $InputObject -and $InputObject -is [System.IDisposable])
{
$InputObject.Dispose()
}
}
}
回答18:
I use this snippet to check my database backups folder for backup files not compressed yet, compress them using 7-Zip, and finally deleting the *.bak
files to save some disk space.
Notice files are ordered by length (smallest to biggest) before compression to avoid some files not being compressed.
$bkdir = \"E:\\BackupsPWS\"
$7Zip = \'C:\\\"Program Files\"\\7-Zip\\7z.exe\'
get-childitem -path $bkdir | Sort-Object length |
where
{
$_.extension -match \".(bak)\" -and
-not (test-path ($_.fullname -replace \"(bak)\", \"7z\"))
} |
foreach
{
$zipfilename = ($_.fullname -replace \"bak\", \"7z\")
Invoke-Expression \"$7Zip a $zipfilename $($_.FullName)\"
}
get-childitem -path $bkdir |
where {
$_.extension -match \".(bak)\" -and
(test-path ($_.fullname -replace \"(bak)\", \"7z\"))
} |
foreach { del $_.fullname }
Here you can check a PowerShell script to backup, compress and transfer those files over FTP.
回答19:
In case you have WinRAR installed:
function ZipUsingRar([String] $directory, [String] $zipFileName)
{
Write-Output \"Performing operation \"\"Zip File\"\" on Target \"\"Item: $directory Destination:\"
Write-Output ($zipFileName + \"\"\"\")
$pathToWinRar = \"c:\\Program Files\\WinRAR\\WinRar.exe\";
[Array]$arguments = \"a\", \"-afzip\", \"-df\", \"-ep1\", \"$zipFileName\", \"$directory\";
& $pathToWinRar $arguments;
}
The meaning of the arguments: afzip creates zip archive, df deletes files, ep1 does not create full directory path within archive
回答20:
Here a complete command line example to launch from cmd.exe or from ssh or what you want !
powershell.exe -nologo -noprofile -command \"&{ Add-Type -A \'System.IO.Compression.FileSystem\' [System.IO.Compression.ZipFile]::CreateFromDirectory(\'c:/path/to/source/folder/\', \'c:/path/to/output/file.zip\');}\"
Regards
回答21:
Loading the [System.IO.IOException]
class and using its methods is an important step in order to suppress unwanted errors, due the fact that it\'s a class not native to PowerShell, so expect various contexts of errors without it.
I error-controlled my script to the T, but got a lot of extra red \'file exists\' output while using [System.IO.Compression.ZipFile]
class
function zipFiles(
[Parameter(Position=0, Mandatory=$true]
[string] $sourceFolder,
[Parameter(Position=1, Mandatory=$true]
[string]$zipFileName,
[Parameter(Position=2, Mandatory=$false]
[bool]$overwrite)
{
Add-Type -Assembly System.IO
Add-Type -Assembly System.IO.Compression.FileSystem
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
$directoryTest = (Test-Path $dailyBackupDestFolder)
$fileTest = (Test-Path $zipFileName)
if ( $directoryTest -eq $false)
{
New-Item -ItemType Directory -Force -Path $dailyBackupDestFolder
}
if ( $fileTest -eq $true)
{
if ($overwrite -eq $true ){Remove-Item $zipFileName}
}
try
{
[System.IO.Compression.ZipFile]::CreateFromDirectory($sourceFolder,$zipFileName,$compressionLevel)
}
catch [System.IO.IOException]
{
Write-Output ($dateTime + \' | \' + $_.Exception.Message ) | Out-File $logFile -append -force
}
}
What I am doing here is catching these IO Errors, such as accessing files that exist already, catching that error and directing it to a logfile that I am maintaining with a larger program.
回答22:
Complete command-line Commands in Windows for Compressing and Extracting Directory is as follows:
For Compression:
powershell.exe -nologo -noprofile -command \"& { Add-Type -A \'System.IO.Compression.FileSystem\'; [IO.Compression.ZipFile]::CreateFromDirectory(\'C:\\Indus\',\'C:\\Indus.zip\'); }\"
For Extracting:
powershell.exe -nologo -noprofile -command \"& { Add-Type -A \'System.IO.Compression.FileSystem\';[IO.Compression.ZipFile]::ExtractToDirectory(\'C:\\Indus.zip\',\'C:\\Indus\'); }\"
回答23:
The ionic approach rocks:
https://dotnetzip.codeplex.com/wikipage?title=PS-Examples
supports passwords, other crypto methods, etc.
回答24:
This script iterates all directories and zip each one
Get-ChildItem -Attributes d | foreach {write-zip $.Name \"$($.Name).zip\"}