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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With