1

we have windows 2012 servers and we have powershell version 3. I'm trying to zip log files individually in a folder based on date condition. Compress-Archive is not available in version 3. we do not have any 3rd party zip utilities like WinZip, 7z..etc I tried using [System.IO.Compression.ZipFile] class but it has no flexibility to zip individual files.

My requirement is, to capture the log files based on date and send them through loop to zip each file and delete original file. Your help in this regard is much appreciated.

Thanks in advance.

Ankababu
  • 13
  • 3
  • I would upgrade Powershell on the server to version 5. – bluuf Dec 22 '21 at 09:44
  • 1
    if upgrading PowerShell is not an option then consider doing this on a server/computer that does have a later version of PowerShell, either remotely or by copying the files locally then copying them back – Otter Dec 22 '21 at 09:47
  • Thanks for taking your time to answer my question. Upgrade is not an option for me here. Process of copying files to share and zipping them is tedious job. – Ankababu Dec 22 '21 at 11:58
  • As a headache as it is COM is the only alternative without using a third party tool – Santiago Squarzon Dec 22 '21 at 16:01
  • move the file to a dedicated temp dir and use `[System.IO.Compression.ZipFile] ` on that. – Lee_Dailey Dec 30 '21 at 06:06

2 Answers2

1

This answer works fine - it's using COM rather than pure .NET methods:

https://serverfault.com/a/456496/204875

Although, to be honest, I highly recommend downloading the portable version of 7zip and using that. No installation required, a lot more efficient and faster. If you can distribute a script, you can usually distribute an exe with it (although, yes, some environments are highly regulated).

Example:

$srcdir = "C:\tmp\in"
$zipFilepath = "C:\tmp\out"
$files = Get-ChildItem -Path $srcdir | where{! $_.PSIsContainer}

foreach($file in $files) { 
    $zipFilename = $file.name -replace '\.\w+$','.zip'
    $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  
    }
    else { 
        # exit loop if zipfile with same name exists
        write-warning "$zipfile exists" 
        Continue
    }
    # create new COM object
    $shellApplication = new-object -com shell.application
    $zipPackage = $shellApplication.NameSpace($zipFile)
    $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 -milliseconds 250
    }
}
write-host "zipfiles created"

Result:

> dir -Recurse
   Directory: C:\tmp\in

Mode                 LastWriteTime         Length Name    
----                 -------------         ------ ----    
-a----        30/12/2021   4:12 pm           5157 txt1.txt
-a----        30/12/2021   4:12 pm           5157 txt2.txt
-a----        30/12/2021   4:12 pm           5157 txt3.txt
-a----        30/12/2021   4:12 pm           5157 txt4.txt


    Directory: C:\tmp\out

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        30/12/2021   4:13 pm           1997 txt1.zip
-a----        30/12/2021   4:14 pm           1997 txt2.zip
-a----        30/12/2021   4:14 pm           1997 txt3.zip
-a----        30/12/2021   4:14 pm           1997 txt4.zip
LeeM
  • 1,118
  • 8
  • 18
  • Thanks for your time LeeM. Unfortunately, the link you provided has a code to zip multiple files into one zip file. My requirement is to read all txt files and zip them individually. Later, I need to delete original txt file. – Ankababu Dec 28 '21 at 13:58
  • Sorry not to be clear - this method can be adapted to do one file at a time. Basically, you would do the `Get-ChildItem` for the dir contents, then nearly everything else in the script moves *inside* the `Foreach ($file...)` loop - create a unique target zipfile name, create a new `$zippackage` with the new zipfile name, copy `$file` to `$zippackage` (just one file), then go to the next loop and repeat all that again with the next `$file`. – LeeM Dec 30 '21 at 01:21
  • I added an example in my original answer. You can see how inefficient the compression is, but it's better than nothing. Another solution I've used for a similar problem is to create a compressed "Archive" subfolder in each directory and simply move files to it - that's a bit faster, especially for smaller files. – LeeM Dec 30 '21 at 05:30
  • Thank you very much @LeeM. I will try this and let you know :) – Ankababu Dec 31 '21 at 11:38
  • Great! And thanks for marking the answer :-) – LeeM Jan 04 '22 at 00:12
0

This solution has been thoroughly tested on Windows Server 2012 and doesn't require the shell COM object. Consequently it can run unattended. I have scheduled it to run daily via Windows Task Scheduler.

Rich Moss
  • 2,195
  • 1
  • 13
  • 18