Need recursive zip script to zip parent folder and items more than 7 days old

Hi there,

I have a PS script which does a great job of finding log files more than 7 days old and spitting them out to another disk as zip files. The only problem is it zips all of the log files older than 7 days as individual files rather than what I want, which is for it to find files older than 7 days and zip them in a single zip file with the parent folder name.

For example in C:\inetpub\logs\LogFiles I have the following folder structure:

C:\inetpub\logs\LogFiles\W3SVC1\logs.txt,logs2.txt etc
C:\inetpub\logs\LogFiles\W3SVC2\logs.txt,logs2.txt etc

Both contain lots of txt log files.

I want to look at these txt files, zip those older than 7 days, then output a single zip file for each W3SVC folder named the same as each W3SVC folder containing the log files older than 7 days from the original W3SVC folder.

This is the script I have so far but I’m not sure how to change the logic so that it does the above:


#usage: new-zip c:\demo\myzip.zip
function New-Zip
{
param([string]$zipfilename)
set-content $zipfilename (“PK” + [char]5 + [char]6 + (“$([char]0)” * 18))
(dir $zipfilename).IsReadOnly = $false
}

#usage: dir c:\demo\files*.* -Recurse | add-Zip c:\demo\myzip.zip
function Add-Zip
{
param([string]$zipfilename)

if(-not (test-path($zipfilename)))
{
	set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
	(dir $zipfilename).IsReadOnly = $false	
}

$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipfilename)

foreach($file in $input) 
{ 
        $zipPackage.CopyHere($file.FullName)
        Start-sleep -milliseconds 500
}

}

$targetFolder = 'C:\inetpub\logs\Test'
$destinationFolder = 'D:\TestLogZip'
$now = Get-Date
$days = 7
$lastWrite = $now.AddDays(-$days)

Get-ChildItem $targetFolder -Recurse | Where-Object { $_ -is [System.IO.FileInfo] } | ForEach-Object {
If ($.LastWriteTime -lt $lastWrite)
{
$
| New-Zip $($destinationFolder + $.BaseName + “.zip”)
$
| Add-Zip $($destinationFolder + $_.BaseName + “.zip”)
}
}


Any help you can give would be greatly appreciated :slight_smile:

Thanks

Sam

There is a Compress-Archive cmdlet in newer versions of Powershell

Unfortunately it do not support folders in archive for individual files, so
I can suggest yoyu to move files which need to be archived in separate folder (with parent folder structure) and compress it into zip by any of available methods

The alternatives also can be direct .net usage of System.IO.Compression.ZipArchive
or Ionic.Zip.ZipFile (I prefer GitHub - haf/DotNetZip.Semverd: A fork of the DotNetZip project without signing with a solution that compiles cleanly. This project aims to follow semver to avoid versioning conflicts. DotNetZip is a FAST, FREE class library and toolset for manipulating zip files. Use VB, C# or any .NET language to easily create, extract, or update zip files.)

You can use .Net system.io.compression.filesystem to create a zip file from a directory, which keeps the structure intact.

#Copy all or move all of your logs to a temporary folder IE: c:\temp\ziptheselogs\

Add-Type -Assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory("c:\temp\ziptheselogs","c:\archive\archivedlogs.zip")

#delete your temporary folder

Looking at this compression - Zipping only files using powershell - Server Fault
and this Delete files older than 15 days using PowerShell - Stack Overflow

I came up with this. This should zip all files in a folder older than 7 days and then remove them.
$limit = (get-date).AddDays(-7)
$srcdir = “c:\test”
$zipFilename = “test.zip”
$zipFilepath = "c:\temp"
$zipFile = “$zipFilepath$zipFilename”

#Prepare zip file
if(-not (test-path($zipFile))) {
set-content $zipFile (“PK” + [char]5 + [char]6 + (“$([char]0)” * 18))
(dir $zipFile).IsReadOnly = $false
}

$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipFile)
$files = Get-ChildItem -Path $srcdir | where{! $.PSIsContainer -and $.CreationTime -lt $limit}

foreach($file in $files) {
$zipPackage.CopyHere($file.FullName)
#using this method, sometimes files can be ‘skipped’
#this ‘while’ loop checks each file is added before moving to the next
while($zipPackage.Items().Item($file.name) -eq $null){
Start-sleep -seconds 1
}
}

Get-ChildItem -Path $srcdir -Recurse -Force | Where-Object { !$.PSIsContainer -and $.CreationTime -lt $limit } | Remove-Item -Force

Thanks Curtis that works on a basic level but doesn’t have the logic to find files older than 7 days or name the destination directory the name of the parent dir.

Thanks Simon that’s so very close to what I need but it doesn’t retain the parent folder name and create a zip with that name. I’m currently toying between your version and mine to see if I can cobble them together and use the parent folder name for the resulting zip filename. Much appreciated input!

Ah, no. The resulting zip file is empty when I use this:

$limit = (get-date).AddDays(-7)
$srcdir = "C:\inetpub\logs\Test"
$zipFilename = “test.zip”
$zipFilepath = "D:\TestLogZip"
$zipFile = “$zipFilepath$zipFilename”

#Prepare zip file
if(-not (test-path($zipFile))) {
set-content $zipFile (“PK” + [char]5 + [char]6 + (“$([char]0)” * 18))
(dir $zipFile).IsReadOnly = $false
}

$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipFile)
$files = Get-ChildItem -Path $srcdir | where{! $.PSIsContainer -and $.CreationTime -lt $limit}

foreach($file in $files) {
$zipPackage.CopyHere($file.FullName)
#using this method, sometimes files can be ‘skipped’
#this ‘while’ loop checks each file is added before moving to the next
while($zipPackage.Items().Item($file.name) -eq $null){
Start-sleep -seconds 1
}
}

Get-ChildItem -Path $srcdir -Recurse -Force | Where-Object { !$.PSIsContainer -and $.CreationTime -lt $limit } | Remove-Item -Force

you have

$srcdir = "C:\inetpub\logs\Test"

try

$srcdir = “C:\inetpub\logs\Test”

I will look at getting the foldername as the zip name

screenshot

Sadly that’s not working either :frowning:

ok try this. It should create a zip file with the source directory name and today’s date as its name

$a = Get-Date -format “ddMMyyyy”
$limit = (get-date).AddDays(-7)
$srcdir = “c:\test”
$name=[System.IO.Path]::GetFileName($srcdir)
$zipFilename = $name + $a + “.zip”
$zipFilepath = "c:\temp"
$zipFile = “$zipFilepath$zipFilename”

#Prepare zip file
if(-not (test-path($zipFile))) {
set-content $zipFile (“PK” + [char]5 + [char]6 + (“$([char]0)” * 18))
(dir $zipFile).IsReadOnly = $false
}

$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipFile)
$files = Get-ChildItem -Path $srcdir | where{! $.PSIsContainer -and $.CreationTime -lt $limit}

foreach($file in $files) {
$zipPackage.CopyHere($file.FullName)
#using this method, sometimes files can be ‘skipped’
#this ‘while’ loop checks each file is added before moving to the next
while($zipPackage.Items().Item($file.name) -eq $null){
Start-sleep -seconds 1
}
}

Get-ChildItem -Path $srcdir -Recurse -Force | Where-Object { !$.PSIsContainer -and $.CreationTime -lt $limit } | Remove-Item -Force

Thanks, it still creates a corrupt zip unfortunately. I’ve tried adding/removing the slashes at the ends of both srcdir and zipFilepath but that doesn’t seem to help :frowning:

strange works fine on my machine. I have created and restored the resulting zip several times. Do you get any errors ?
Just in case it make any difference I am running on Windows 7 (I know…)

PS M:> $PSVersionTable.PSVersion

Major Minor Build Revision


5 0 10586 117

I end up with a zip files called test25082017.zip that I can open and restore all of the content

That’s odd. I’m using this on Windows Server 2012:

PS C:\windows\system32> $PSVersionTable.PSVersion

Major Minor Build Revision


4 0 -1 -1

Just a thought try are using $srcdir = “C:\inetpub\logs\Test” do you have permission to that dir? Try moving the contents to a test or temp dir and pointing the script at that

Also I ran it from the ISE

Thanks, it was something I hadn’t thought about but still get the same result despite moving srcdir to a dir I have full control over :frowning:

MMM I am at a bit of a loss then as it works fine here :frowning: what exactly do you end up with ? i.e. an empty zip file ? Another idea is to comment out the delete part and change $limit = (get-date).AddDays(-7) to $limit = (get-date) so it sees today’s files, as it maybe some strange time stamp thing on your files.

The only way I can reproduce the error you get is if $files is empty i.e. there are not any files newer than 7 days in the directory. After I ran the script again in the window of the ISE I typed $files and it listed the files newer than 7 days and $files.cont told me how many.
PS M:> $files

Directory: C:\test

Mode LastWriteTime Length Name


         01/08/2017     15:12            434 01-12-2017results.csv                                               
         14/08/2017     15:40            664 14-40-2017results.csv                                               
         08/08/2017     13:15            194 1lines.csv                                                          
         08/08/2017     12:53            194 2lines.csv                                                          
         16/08/2017     08:29            441 basetext.txt                                                        
         16/08/2017     08:32           1520 converted.xml                                                       
         04/08/2017     09:59             10 decripted.txt                                                       
         17/08/2017     09:43        4981040 help.txt                                                            
         14/08/2017     15:40         387385 MSRC_CVEs2017-Jul.csv                                               
         14/08/2017     15:40        1618222 MSRC_CVEs2017-Jul.html                                              
         10/08/2017     12:15             66 name.csv                                                            
         02/08/2017     14:39          16856 power.txt                                                           
         04/08/2017     09:57             62 secure.txt                                                          
         17/08/2017     12:33             10 servernames.txt                                                     
         10/08/2017     12:16             20 test2.csv                                                           
         14/08/2017     13:01          10782 testupdates.xlsx                                                    
         04/08/2017     10:35             18 tocopy.txt                                                          
         08/08/2017     13:25            214 withdate.csv                                                        

PS M:> $files.count
18

PS M:>

If I then run it again (without restoring the files I get this when testing $files
PS M:> C:\Powershell Scripts\folercleanup.ps1

PS M:> $files

PS M:> $files.count
0

PS M:>

Which results in an empty zip file like you have. Can you test that $files has something in it ?

Screenshot

Yes it does contain files in the last 7 days.

This is weird, must be a difference between the PS versions and possibly OS?

Thanks again for your help!

Maybe someone else here has an idea as I am out of them and don’t have a 2012 server to test it on. Maybe you could try it on another machine / operating system or something. Anyway good luck and let me know how you get on :slight_smile:

Based on your original post, you already have that logic.

“I have a PS script which does a great job of finding log files more than 7 days old and spitting them out to another disk”