简体   繁体   中英

Compress files in folder to zip file by using PS

I have the following scripts to compress a folder (all files in the folder) to a zip file:

 set-content $zipFileName ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18)) 
 $ZipFile = (new-object -com shell.application).NameSpace($zipFileName) 
 Get-ChildItem $folder | foreach {$zipFile.CopyHere($_.fullname)} 

where $folder = "C:\\Test", and $zipFileName = "C:\\data\\test.zip" as example

It works fine if "C:\\Test" contains no empty sub-folders, and it seems works recursively to compress all files within sub-folders. I really like above simple line script. For example:

C:\Test
   file1.dat
   file2.dat
   Test-Sub
      File21.bat
      ....

However, I got error in one case. I find that if there is any empty folder such as "C:\\Test\\EmptySub",

C:\Test
   file1.dat
   file2.dat
   Test-Sub
      File21.bat
      ....
   EmptySub
   AnotherSub
      file31.sp1
      ...

the script will generate an error. I tried the following scripts:

Get-ChildItem $files -Recurse | foreach { if (!$_.PSIsContainer) 
    {$zipFile.CopyHere($_.fullname)}} 

This does not work as expected. It just skips all the sub-folders. Not sure if there are filter or clause available to skip all the empty sub-folders?

Updated : Based on suggests, I gave it a try. My problem has not be resolved. Here is the update of my question. First, I updated the scripts above to show how $zipFile object is created. Secondly I have the suggested codes:

Get-ChildItem $files | ? {-not ($_.PSIsContainer -eq $True -and 
  $_.GetFiles().Count -eq 0) } | % {$zipfile.CopyHere($_.fullname)}

I tried above updates on my WindowsXP, it works fine with empty sub-folders. However, the same codes do not workin in Windows 2003 Server. The following is the error message:

[Window Title] Compressed (zipped) Folders Error

[Content] File not found or no read permission.

[OK]

Not sure if this type PK object works in Windows 2003 server, or if there is other settings for the object.

You can detect empty directories by testing against an empty return from get-childitem. For example, this will return the list of empty directories

dir | where{$_.PSIsContainer -and -not (gci $_)}

Though in your case, you want the inverse:

Get-ChildItem $files | where{-not ($_.PSIsContainer -and -not (gci $_))} | foreach {$zipfile.CopyHere($_.fullname)}} 

Your code works recursively in the sense that you get any kind of child item (folders included). If your intention is to exclude empty folder you should filter them:

Try this one liner:

gci $folder |`
? {-not ($_.PSIsContainer -eq $True -and $_.GetFiles().Count -eq 0) } |`
% {$zipfile.CopyHere($_.fullname)}

Here is the function I created to zip files. The reason why you are getting the read error is because .CopyHere is an asynchronous copy process, so my script verifies the file exists in the zip file before continuing to the next file to zip:

function Out-ZipFile ([string]$path) 
{ 
    try
    {
        $files = $input

        if ($path.StartsWith(".\")) { $path=$path.replace(".\","$($pwd)\") }
        if (-not $path.Contains("\")) { $path="$($pwd)\$($path)" }
        if (-not $path.EndsWith('.zip')) {$path += '.zip'} 

        if (-not (test-path $path)) { 
          set-content $path ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18)) 
        } 

        $ZipFile = (new-object -com shell.application).NameSpace($path) 
        $files | % { 
            $FileName = $_.name
            "Adding $FileName to $path"; 
            $ZipFile.CopyHere($_.fullname);  
            While (($ZipFile.Items() | where { $_.Name -like $FileName }).Size -lt 1) { Start-Sleep -m 100 };
        } 
    }
    catch
    {
        write-output "Error Encountered: `n$_"
        return $_
        throw
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM