2014-04-02 178 views
6

我知道很多已經使用Powershell壓縮文件的內容,但是我找不到一個完全符合我需要的方法。Powershell Zip文件夾內容

我希望能夠壓縮文件夾和文件爲.zip文件夾,而無需Zip文件裏的父文件夾。因此,例如,我有一個名爲STUFF的文件夾,其中包含文件/文件夾,我想將其壓縮到名爲STUFF.zip的文件夾中。然後,該文件夾的結構將是STUFF.zip>文件/文件夾不STUFF.zip> STUFF>文件/文件夾,因爲我目前得到使用此代碼...

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 + ").") 
} 

使用

Remove-Item "H:\STUFF.zip" 

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

完全學分制對此代碼使用here。我非常感謝任何幫助,這項功能對我的項目至關重要!不幸的是,我不能使用社區擴展模塊,因爲其他PC上運行的這個模塊沒有安裝這個模塊。

謝謝!

+0

Dotnet 4.5增加了zip功能,應該給你比COM方法更好的選擇。其他電腦有嗎? – mjolinor

回答

6

如果使用PSCX Module您將使用下面的代碼行,以獲得您所需要的:

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

按照@mjolinor「H:\東西\」,如果你有.NET 4.5安裝,您可以運行以下內容:

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

新的解決方案可提供WMF 5(遠的不說新^^)

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