2014-04-02 1 views
6

Ich weiß, dass beim Zippen von Dateien mit Powershell viel geübt wurde, aber ich finde keine Methode, die genau das tut, was ich brauche.Powershell Zip-Ordner Inhalt

Ich möchte Ordner UND Dateien in einem ZIP-Ordner komprimieren können, ohne den übergeordneten Ordner in der ZIP. So habe ich zum Beispiel einen Ordner namens STUFF, der Dateien/Ordner enthält, den ich in einen Ordner namens STUFF.zip zippen möchte. Diese Ordner-Struktur wäre dann STUFF.zip> Dateien/Ordner NICHT STUFF.zip> STUFF> Dateien/Ordner, wie ich zur Zeit dieses Code erhalten mit ...

function CountZipItems(
[__ComObject] $zipFile) 
{ 
If ($zipFile -eq $null) 
{ 
    Throw "Value cannot be null: zipFile" 
} 

Write-Host ("Counting items in zip file (" + $zipFile.Self.Path + ")...") 

[int] $count = CountZipItemsRecursive($zipFile) 

Write-Host ($count.ToString() + " items in zip file (" ` 
    + $zipFile.Self.Path + ").") 

return $count 
} 

function CountZipItemsRecursive(
[__ComObject] $parent) 
{ 
If ($parent -eq $null) 
{ 
    Throw "Value cannot be null: parent" 
} 

[int] $count = 0 

$parent.Items() | 
    ForEach-Object { 
     $count += 1 

     If ($_.IsFolder -eq $true) 
     { 
      $count += CountZipItemsRecursive($_.GetFolder) 
     } 
    } 

return $count 
} 

function IsFileLocked(
[string] $path) 
{ 
If ([string]::IsNullOrEmpty($path) -eq $true) 
{ 
    Throw "The path must be specified." 
} 

[bool] $fileExists = Test-Path $path 

If ($fileExists -eq $false) 
{ 
    Throw "File does not exist (" + $path + ")" 
} 

[bool] $isFileLocked = $true 

$file = $null 

Try 
{ 
    $file = [IO.File]::Open(
     $path, 
     [IO.FileMode]::Open, 
     [IO.FileAccess]::Read, 
     [IO.FileShare]::None) 

    $isFileLocked = $false 
} 
Catch [IO.IOException] 
{ 
    If ($_.Exception.Message.EndsWith(
     "it is being used by another process.") -eq $false) 
    { 
     Throw $_.Exception 
    } 
} 
Finally 
{ 
    If ($file -ne $null) 
    { 
     $file.Close() 
    } 
} 

return $isFileLocked 
} 

function GetWaitInterval(
[int] $waitTime) 
{ 
If ($waitTime -lt 1000) 
{ 
    return 100 
} 
ElseIf ($waitTime -lt 5000) 
{ 
    return 1000 
} 
Else 
{ 
    return 5000 
} 
} 

function WaitForZipOperationToFinish(
[__ComObject] $zipFile, 
[int] $expectedNumberOfItemsInZipFile) 
{ 
If ($zipFile -eq $null) 
{ 
    Throw "Value cannot be null: zipFile" 
} 
ElseIf ($expectedNumberOfItemsInZipFile -lt 1) 
{ 
    Throw "The expected number of items in the zip file must be specified." 
} 

Write-Host -NoNewLine "Waiting for zip operation to finish..." 
Start-Sleep -Milliseconds 1000 # ensure zip operation had time to start 

[int] $waitTime = 0 
[int] $maxWaitTime = 60 * 1000 # [milliseconds] 
while($waitTime -lt $maxWaitTime) 
{ 
    [int] $waitInterval = GetWaitInterval($waitTime) 

    Write-Host -NoNewLine "." 
    Start-Sleep -Milliseconds $waitInterval 
    $waitTime += $waitInterval 

    Write-Debug ("Wait time: " + $waitTime/1000 + " seconds") 

    [bool] $isFileLocked = IsFileLocked($zipFile.Self.Path) 

    If ($isFileLocked -eq $true) 
    { 
     Write-Debug "Zip file is locked by another process." 
     Continue 
    } 
    Else 
    { 
     Break 
    } 
} 

Write-Host       

If ($waitTime -ge $maxWaitTime) 
{ 
    Throw "Timeout exceeded waiting for zip operation" 
} 

[int] $count = CountZipItems($zipFile) 

If ($count -eq $expectedNumberOfItemsInZipFile) 
{ 
    Write-Debug "The zip operation completed succesfully." 
} 
ElseIf ($count -eq 0) 
{ 
    Throw ("Zip file is empty. This can occur if the operation is" ` 
     + " cancelled by the user.") 
} 
ElseIf ($count -gt $expectedCount) 
{ 
    Throw "Zip file contains more than the expected number of items." 
} 
} 

function ZipFolder(
[IO.DirectoryInfo] $directory) 
{ 
If ($directory -eq $null) 
{ 
    Throw "Value cannot be null: directory" 
} 

Write-Host ("Creating zip file for folder (" + $directory.FullName + ")...") 

[IO.DirectoryInfo] $parentDir = $directory.Parent 

[string] $zipFileName 

If ($parentDir.FullName.EndsWith("\") -eq $true) 
{ 
    # e.g. $parentDir = "C:\" 
    $zipFileName = $parentDir.FullName + $directory.Name + ".zip" 
} 
Else 
{ 
    $zipFileName = $parentDir.FullName + "\" + $directory.Name + ".zip" 
    #$zipFileName = $directory.Name + ".zip" 
    #$zipFileName = $parentDir.FullName + ".zip" 
} 

If (Test-Path $zipFileName) 
{ 
    Throw "Zip file already exists ($zipFileName)." 
} 

Set-Content $zipFileName ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18)) 

$shellApp = New-Object -ComObject Shell.Application 
$zipFile = $shellApp.NameSpace($zipFileName) 

If ($zipFile -eq $null) 
{ 
    Throw "Failed to get zip file object." 
} 

[int] $expectedCount = (Get-ChildItem $directory -Force -Recurse).Count 
$expectedCount += 1 # account for the top-level folder 

$zipFile.CopyHere($directory.FullName) 
#Get-ChildItem $directory | foreach {$zipFile.CopyHere($_.fullname)} 

# wait for CopyHere operation to complete 
WaitForZipOperationToFinish $zipFile $expectedCount 

Write-Host -Fore Green ("Successfully created zip file for folder (" ` 
    + $directory.FullName + ").") 
} 

Nutzungs

Remove-Item "H:\STUFF.zip" 

[IO.DirectoryInfo] $directory = Get-Item "H:\STUFF" 
ZipFolder $directory 

kompletter Kredit geht für diesen Code here. Ich schätze jede Hilfe, die ich bekomme, diese Fähigkeit ist entscheidend für mein Projekt! Leider kann ich das Community Extension-Modul nicht verwenden, da andere PCs, auf denen dieses Programm ausgeführt wird, dieses Modul nicht installiert haben.

Danke!

+0

Dotnet 4.5 hinzugefügt Zip-Funktionalität, die Ihnen bessere Optionen als die COM-Methoden geben sollte. Haben die anderen PCs das? – mjolinor

Antwort

6

Wenn Sie PSCX Module Sie die Zeile Code unten verwenden zu bekommen, was Sie brauchen:

write-zip h:\Stuff\* myzipfile.zip 
14

Per @mjolinor "H: \ Stuff \", wenn Sie Sie können .NET 4.5 installiert haben laufen die folgenden:

$src = "H:\Stuff\" 
$dst = "H:\Stuff.zip" 
[Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") 
[System.IO.Compression.ZipFile]::CreateFromDirectory($src, $dst) 
1

neue Lösung zur Verfügung mit WMF 5 (auch nicht, dass neue ^^)

Compress-Archive -Path H:\stuff\* -DestinationPath H:\stuff.zip -Force