2014-04-02 3 views
6

Powershell을 사용하여 파일을 지퍼로 묶는 방법에 대해서는 많은 지식이 있지만 필자가 필요로하는 방식을 찾을 수는 없습니다.Powershell Zip 폴더 내용

zip 내에 상위 폴더가 없어도 폴더와 파일을 .zip 폴더로 압축 할 수 있기를 원합니다. 예를 들어 파일/폴더가 들어있는 STUFF라는 폴더가 있는데 STUFF.zip이라는 폴더에이 폴더를 압축하고 싶습니다. 이 폴더 구조는 다음 STUFF.zip> 파일/폴더 NOT 것 STUFF.zip> 다도> 파일/폴더 나는 현재 ...

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 방식보다 더 나은 옵션을 제공합니다. 다른 PC에도 그렇게 있습니까? – mjolinor

답변

6

당신은 당신이 당신이 필요로하는 것을 얻기 위해 아래의 라인 코드를 사용 PSCX Module 사용하는 경우 : 당신은 당신이 실행할 수 있습니다 설치된 .NET 4.5이있는 경우 :

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

@mjolinor 당으로 "\ 물건 \ H를" 다음

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

새로운 솔루션으로 (물론하지를 그 새 ^^)

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