Few weeks ago I needed to free some space form a disk on a Windows Server 20012 R2, so I wanted to compress a large number folders, each one of them contained few hundred MB of log files. It required to preserve the folder name and deleting or moving the files or directory from that volume/partition was not an option.
“It’s an easy task with PowerShell“, I thought, “I can re-use one of my functions or scripts“.
In fact, few months ago I’ve published an article on how to compress a folder, but to re-use that specific code on that environment I needed to install 7zip (which in this specific case I tried to avoid), because the cmd-let Compress-Archive was released with version 5 and the server is using PowerShell 4. So I needed to revisit my script that wasn’t ready to go and solve my problem without a little tweak.
My solution was to point to directly to the ZipFile Class from the .NETFramework, using PowerShell. As you can probably guess, the main advantage of using PowerShell is that can access directly .NET Framework if needed, PowerShell is built upon it. Just remember the difference with PowerShell 6 or later(or core) that are built upon .NET core. Then I’ve found another blog post of the scripting guys that were doing exactly the same, so I though that I was on the right track if their conclusions were the same.
So I’ve written a function tested for version of powershell / powershell core and os-independent. A wrapper for the cmd-let Compress-Archive for version 5 and later (including powershell core) and leveraging the .NET Framework for older versions. In short, I try to my old scripts a backward compatibility feature, not just multi-platform.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
function Compress-Folder { <# .SYNOPSIS Compress a folder and remove the directory if needed. .DESCRIPTION This function is a wrapper of Compress-Archive for PowerShell versions greater or equal to 5 or if not it leverages ZipFile class from .NET Framework to achieve the same result providing backward compatibility. If RemoveDirWhenFinished parameter is set to $True the target directory will be removed after compression. .PARAMETER FolderName FolderName parameter is required to specify which folder you want to compress .PARAMETER RemoveDirWhenFinished RemoveDirWhenFinished parameter is optional, if the compression task succeeded and the parameter is set to $True the "FolderName" target directory will be removed. .EXAMPLE Compress-Folder -FolderName "/Users/paolofrigo/Documents/tmp_folder_01" Creates an archive named "tmp_folder_01.zip" on the parent path. .EXAMPLE Compress-Folder -FolderName "D:\Logs\temp01" -RemoveDirWhenFinished $True Creates an archive named "temp01.zip" and it removes the folder when finished. .NOTES Author: [email protected], https://www.scriptinglibrary.com #> [CmdletBinding()] # Add cmdlet features. Param ( [Parameter(Mandatory = $True)] [string]$FolderName, [Parameter(Mandatory = $False)] [bool]$RemoveDirWhenFinished ) Begin { $PSVersion = $PSVersionTable.PSVersion.Major $FolderNameFullPath=(Resolve-Path $FolderName).Path $DestinationFullPath="$FolderNameFullPath.zip" $Destination = "$Foldername.zip" } Process { if (Test-Path -path $FolderNameFullPath) { If (Test-path $DestinationFullPath) { Remove-Item $DestinationFullPath #-confirm } try { if (($PSVersion -ge 5) -and (Get-ChildItem -path $FolderNameFullPath).count -gt 0) { Compress-Archive -Path $FolderNameFullPath -DestinationPath $DestinationFullPath -Force -CompressionLevel Optimal } else { Add-Type -assembly "system.io.compression.filesystem" [io.compression.zipfile]::CreateFromDirectory($FolderNameFullPath, $DestinationFullPath) } Write-Verbose "Archive Created: $Destination" if ((test-path -path $DestinationFullPath) -and $RemoveDirWhenFinished -eq $True) { Remove-Item -Recurse -path $FolderNameFullPath Write-Verbose "$FolderName removed." } } catch { Write-Error "Compression failed for $FolderName" } } else { Write-Error "Path not valid $FolderNameFullPath" } } End { } } |
Remember to import the function before call it, with the dot-sourcing method, and always read the docs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
PS /Users/paolofrigo/Documents/scriptinglibrary/Blog/PowerShell> get-help Compress-Folder NAME Compress-Folder SYNOPSIS Compress a folder and remove the directory if needed. SYNTAX Compress-Folder [-FolderName] <String> [[-RemoveDirWhenFinished] <Boolean>] [<CommonParameters>] DESCRIPTION This function is a wrapper of Compress-Archive for PowerShell versions greater or equal to 5 or if not it leverages ZipFile class from .NET Framework to achieve the same result providing backward compatibility. If RemoveDirWhenFinished parameter is set to $True the target directory will be removed after compression. RELATED LINKS REMARKS To see the examples, type: "get-help Compress-Folder -examples". For more information, type: "get-help Compress-Folder -detailed". For technical information, type: "get-help Compress-Folder -full". PS /Users/paolofrigo/Documents/scriptinglibrary/Blog/PowerShell> get-help Compress-Folder -Examples NAME Compress-Folder SYNOPSIS Compress a folder and then it removes the directory if needed. -------------------------- EXAMPLE 1 -------------------------- PS C:\>Compress-Folder -FolderName "/Users/paolofrigo/Documents/tmp_folder_01" Creates an archive named "tmp_folder_01.zip" on the parent path. -------------------------- EXAMPLE 2 -------------------------- PS C:\>Compress-Folder -FolderName "D:\Logs\temp01" -RemoveDirWhenFinished $True Creates an archive named "temp01.zip" and it removes the folder when finished. |
If you don’t remember which powershell version is available on which OS… there is an interesting summary on 4sysops.com website that I recommend you to read.
I hope you find this article useful and if you have any question feel free to ask or contact me.