Czy można utworzyć archiwum zip za pomocą programu PowerShell?
Czy można utworzyć archiwum zip za pomocą programu PowerShell?
Odpowiedzi:
Jeśli przejdziesz do CodePlex i przejmiesz rozszerzenia społeczności PowerShell , możesz użyć ich polecenia write-zip
cmdlet.
Od
CodePlex jest w trybie tylko do odczytu w ramach przygotowań do zamknięcia
możesz przejść do Galerii PowerShell .
write-zip [input file/folder] [output file]
Czysta alternatywa PowerShell, która działa z PowerShell 3 i .NET 4.5 (jeśli możesz go użyć):
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)
}
Po prostu podaj pełną ścieżkę do archiwum zip, które chcesz utworzyć, i pełną ścieżkę do katalogu zawierającego pliki, które chcesz spakować.
Dodatki Compress-Archive
i polecenia Expand-Archive
cmdlet programu PowerShell v5.0 . Strony, do których prowadzą linki, mają pełne przykłady, ale ich istotą jest:
# 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
Compress-Archive
opisu: „... maksymalny rozmiar pliku, który można skompresować za pomocą Compress-Archive, wynosi obecnie 2 GB. Jest to ograniczenie podstawowego interfejsu API”. Jeśli jednak użyjesz System.IO.Compression.ZipFile
, możesz ominąć to ograniczenie.
System.IO.Compression.ZipFile
. Jeśli używana platforma .NET nie ma tego limitu, CmdLet nie powinien przekroczyć tego limitu. Zweryfikowałem w kodzie.
-OutputPath
parametru.
Natywny sposób z najnowszą platformą .NET 4.5, ale całkowicie pozbawiony funkcji:
Kreacja:
Add-Type -Assembly "System.IO.Compression.FileSystem" ;
[System.IO.Compression.ZipFile]::CreateFromDirectory("c:\your\directory\to\compress", "yourfile.zip") ;
Ekstrakcja:
Add-Type -Assembly "System.IO.Compression.FileSystem" ;
[System.IO.Compression.ZipFile]::ExtractToDirectory("yourfile.zip", "c:\your\destination") ;
Jak wspomniano, całkowicie pozbawiony funkcji, więc nie oczekuj flagi zastępowania .
AKTUALIZACJA: Zobacz poniżej innych programistów, którzy rozwijali się w tym przez lata ...
Zainstaluj 7zip (lub pobierz wersję wiersza polecenia) i użyj tej metody PowerShell:
function create-7zip([String] $aDirectory, [String] $aZipfile){
[string]$pathToZipExe = "$($Env:ProgramFiles)\7-Zip\7z.exe";
[Array]$arguments = "a", "-tzip", "$aZipfile", "$aDirectory", "-r";
& $pathToZipExe $arguments;
}
Możesz to tak nazwać:
create-7zip "c:\temp\myFolder" "c:\temp\myFolder.zip"
& "C:\Program Files\7-Zip\7z.exe" a -tzip ($file.FullName+".zip") $file.FullName
Lot zmienił się od czasu opublikowania pierwszej odpowiedzi. Oto niektóre z najnowszych przykładów użycia polecenia Compress-Archive .
Polecenie utworzenia nowego pliku archiwum Draft.zip
poprzez kompresję dwóch plików Draftdoc.docx
i diagram2.vsd
określone przez Path
parametr. Poziom kompresji określony dla tej operacji to Optymalny.
Compress-Archive -Path C:\Reference\Draftdoc.docx, C:\Reference\Images\diagram2.vsd -CompressionLevel Optimal -DestinationPath C:\Archives\Draft.Zip
Polecenie, aby utworzyć nowy plik archiwum, Draft.zip
kompresując dwa pliki Draft doc.docx
i Diagram [2].vsd
określone przez LiteralPath
parametr. Poziom kompresji określony dla tej operacji to Optymalny.
Compress-Archive -LiteralPath 'C:\Reference\Draft Doc.docx', 'C:\Reference\Images\Diagram [2].vsd' -CompressionLevel Optimal -DestinationPath C:\Archives\Draft.Zip
Polecenie utworzenia nowego pliku archiwum Draft.zip
w C:\Archives
folderze. Nowy plik archiwum zawiera każdy plik w folderze C: \ Reference , ponieważ zamiast określonych nazw plików w parametrze Path użyto znaku zastępczego .
Compress-Archive -Path C:\Reference\* -CompressionLevel Fastest -DestinationPath C:\Archives\Draft
Command tworzy archiwum z całego folderu, C:\Reference
Compress-Archive -Path C:\Reference -DestinationPath C:\Archives\Draft
PowerShell automatycznie dodaje .zip
rozszerzenie do nazwy pliku.
Edytuj dwa - Ten kod to brzydka, brzydka kluge z dawnych czasów. Nie chcesz tego.
To kompresuje zawartość .\in
do .\out.zip
z System.IO.Packaging.ZipPackage zgodnie z przykładem tutaj
$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()
Edycja: zawodny w przypadku większych plików, może> 10 MB, YMMV. Ma to coś wspólnego z dowodami domeny i izolowanym miejscem do przechowywania. Bardziej przyjazne podejście .NET 4.5 działa dobrze z PS v3, ale w moim przypadku potrzebowałem więcej pamięci. Aby korzystać z .NET 4 z PS v2, pliki konfiguracyjne wymagają nieobsługiwanego usprawnienia .
Podanie poniżej innej opcji. Spowoduje to spakowanie pełnego folderu i zapisanie archiwum do podanej ścieżki o podanej nazwie.
Wymaga platformy .NET 3 lub nowszej
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)
Oto natywne rozwiązanie dla programu PowerShell v5, wykorzystujące polecenie cmdlet Compress-Archive
Tworzenie plików Zip za pomocą programu PowerShell .
Zobacz także dokumentację Microsoft Docs for Compress-Archive .
Przykład 1:
Compress-Archive `
-LiteralPath C:\Reference\Draftdoc.docx, C:\Reference\Images\diagram2.vsd `
-CompressionLevel Optimal `
-DestinationPath C:\Archives\Draft.Zip
Przykład 2:
Compress-Archive `
-Path C:\Reference\* `
-CompressionLevel Fastest `
-DestinationPath C:\Archives\Draft
Przykład 3:
Write-Output $files | Compress-Archive -DestinationPath $outzipfile
Do kompresji użyłbym biblioteki (7-Zip jest dobry, jak sugeruje Michał ).
Jeśli zainstalujesz 7-Zip , zainstalowany katalog będzie zawierał 7z.exe
aplikację konsolową.
Możesz wywołać go bezpośrednio i użyć dowolnej opcji kompresji.
Jeśli chcesz współpracować z biblioteką DLL, powinno to być również możliwe.
7-Zip jest darmowym oprogramowaniem typu open source.
Co System.IO.Packaging.ZipPackage
?
Wymagałoby .NET 3.0 lub nowszej wersji.
#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()
przez Anders Hesselbom
Dlaczego nikt nie patrzy na dokumentację? Istnieje obsługiwana metoda tworzenia pustego pliku zip i dodawania do niego pojedynczych plików wbudowanych w tę samą bibliotekę .NET 4.5, do której wszyscy się odwołują.
Poniżej znajduje się przykład kodu:
# 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()
Zachęcam do przejrzenia dokumentacji, jeśli masz jakieś pytania.
To jest naprawdę niejasne, ale działa. 7za.exe to samodzielna wersja 7zip i jest dostępna z pakietem instalacyjnym.
# 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
}
Jeśli ktoś musi skompresować pojedynczy plik (a nie 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
Oto działający kod, który kompresuje wszystkie pliki z folderu źródłowego i tworzy plik zip w folderze docelowym.
$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.."
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)
}
Uwaga:
ZipName: pełna ścieżka do pliku zip, który chcesz utworzyć.
SourceDirectory: pełna ścieżka do katalogu zawierającego pliki, które chcesz spakować.
Oto nieco ulepszona wersja odpowiedzi sonjza, dodaje opcję zastępowania.
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)
}
Powinno to również działać w przypadku kompresji pojedynczego pliku bez użycia folderu tymczasowego i korzystania z natywnego programu .Net 4.5, przekonwertowanego z C # z odpowiedzi StackOverflow . Używa ładniejszej składni pobranej stąd .
Stosowanie:
ZipFiles -zipFilename output.zip -sourceFile input.sql -filename name.inside.zip.sql
Kod:
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)
}
}
}
Za pomocą:
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()
}
}
}
shell.application
biznesu lub 7-Zip / innych oddzielnych narzędzi. Podoba mi się również ta Using-Object
funkcja, chociaż bez niej wybrałem krótsze, szybkie i brudne podejście.
Używam tego fragmentu, aby sprawdzić folder kopii zapasowych bazy danych w poszukiwaniu jeszcze nieskompresowanych plików kopii zapasowych, skompresować je za pomocą 7-Zip, a na koniec usunąć *.bak
pliki, aby zaoszczędzić trochę miejsca na dysku. Pliki powiadomień są sortowane według długości (od najmniejszej do największej) przed kompresją, aby uniknąć kompresji niektórych plików.
$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 }
Tutaj możesz sprawdzić skrypt PowerShell do tworzenia kopii zapasowych, kompresji i przesyłania tych plików przez FTP .
Jeśli masz zainstalowany WinRAR:
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;
}
Znaczenie argumentów: afzip tworzy archiwum zip, df usuwa pliki, ep1 nie tworzy pełnej ścieżki katalogu w archiwum
Oto kompletny przykład wiersza poleceń do uruchomienia z cmd.exe lub z ssh lub co chcesz!
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');}"
pozdrowienia
Ładowanie [System.IO.IOException]
klasy i korzystanie z jej metod jest ważnym krokiem w celu eliminacji niepożądanych błędów, ponieważ jest to klasa nienatywna dla PowerShell, więc bez niej należy oczekiwać różnych kontekstów błędów.
Skontrolowałem mój skrypt do T, ale dostałem wiele dodatkowych czerwonych wyników „plik istnieje” podczas korzystania z [System.IO.Compression.ZipFile]
klasy
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
}
}
To, co tu robię, polega na wyłapywaniu tych błędów we / wy, takich jak uzyskiwanie dostępu do plików, które już istnieją, przechwytywanie tego błędu i przekierowywanie go do pliku dziennika, który utrzymuję za pomocą większego programu.
Pełne polecenia wiersza polecenia w systemie Windows do kompresji i wyodrębniania katalogu są następujące:
Do kompresji:
powershell.exe -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::CreateFromDirectory('C:\Indus','C:\Indus.zip'); }"
Do wyodrębnienia:
powershell.exe -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem';[IO.Compression.ZipFile]::ExtractToDirectory('C:\Indus.zip','C:\Indus'); }"
Podejście jonowe kołysze:
https://dotnetzip.codeplex.com/wikipage?title=PS-Examples
obsługuje hasła, inne metody kryptograficzne itp.