New Tools - File and Folder Archiver
Let's continue with recent additions to my PowerShell toolbox. Another recurring task is that I often want to create a ZIP file of selected files from a folder. For this newsletter, I occasionally create a zip file of content and share it on Dropbox. Using Compress-Archive
is simple enough. The hurdle was selecting the files I wanted to include.
An Object Picker
If I only need to select files from a given folder, I can easily use Out-ConsoleGridView
, since I'm using PowerShell 7 primarily. I could just as easily use Out-GridView
. If you don't have Out-ConsoleGridView
, install the Microsoft.PowerShell.ConsoleGuiTools
module from the PowerShell Gallery.
Using the Out-ConsoleGridView
cmdlet, I can select files from a folder
dir c:\temp\ -file | Out-ConsoleGridView -Title "Select files" -OutputMode Multiple
This works just like Out-GridView
but in a console window. I can select multiple files and click OK.

The selected files are returned as objects.

New-FolderArchive
Because Compress-Archive
accepts pipeline input, I can easily create a zip file with a one-line expression.
dir c:\temp\ -file | Out-ConsoleGridView -Title "Select files" -OutputMode Multiple | Compress-archive -DestinationPath c:\Work\selected.zip -CompressionLevel Optimal
To make this re-usable, I wrapped the code in a function called New-FolderArchive
.
#requires -version 7.4
#requires -module Microsoft.PowerShell.ConsoleGuiTools
#this function could be revised to use Out-GridView instead of Out-ConsoleGridView.
Function New-FolderArchive {
[cmdletbinding(SupportsShouldProcess)]
[OutputType('System.IO.FileInfo')]
Param(
[Parameter(
Position = 0,
ValueFromPipeline,
HelpMessage = "Specify the folder to use."
)]
[ValidateNotNullOrEmpty()]
[String]$Path = ".",
[Parameter(HelpMessage ="Specify the file name and path for the ZIP archive.")]
[ValidatePattern(".*\.zip$")]
[string]$Archive = ".\Archive.zip"
)
Begin {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)"
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)"
} #begin
Process {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $Path"
$selected = Get-ChildItem -Path $Path -file |
Out-ConsoleGridView -Title "Select files to archive" -OutputMode Multiple
if ($Selected) {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Selected $($Selected.Count) files"
#An existing archive with the same name will be overwritten
if ($PSCmdlet.ShouldProcess("$($Selected.Count) selected files", "Archive to $Archive")) {
$Selected | Compress-Archive -DestinationPath $Archive -CompressionLevel Optimal -Force -PassThru
}
}
} #process
End {
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)"
} #end
} #close New-FolderArchive
Even though Compress-Archive
supports -WhatIf
, I'm writing my own WhatIf
handler so that I can control the message displayed when the function is run with -WhatIf
.
if ($PSCmdlet.ShouldProcess("$($Selected.Count) selected files", "Archive to $Archive")) {
$Selected | Compress-Archive -DestinationPath $Archive -CompressionLevel Optimal -Force -PassThru
}
You should use SupportsShouldProcess
in the cmdletbinding
attribute to enable the -WhatIf
and -Confirm
parameters whenever creating or modifying files.
PS C:\> New-FolderArchive -Path c:\work -Archive c:\temp\Demo.zip -WhatIf
What if: Performing the operation "Archive to c:\temp\Demo.zip" on target "12 selected files".
I expect this will meet most of my needs. However, there may be more complicated scenarios where I need to select files from multiple folders or filter files based on some criteria.
Zip Options
For more granular control over ZIP archives, I can use the System.IO.Compression
class from the .NET Framework. I wrote about this earlier this year.
I can easily create a new ZIP file.
$zip = [System.IO.Compression.ZipFile]::Open("c:\work\FooFoo.zip","Create")
The file you create must not already exist or you'll get an error.
I like that I can add a comment to the ZIP file.
$zip.comment = "This is a demo zip file"
`````
This is already an advantage over `Compress-Archive`.
I have several options for adding items to the ZIP file. I can add a file.
```powershell
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip,"C:\Scripts\1000FemaleNames.txt","1000FemaleNames.txt","SmallestSize")
The parameter syntax is (ZipArchive, source file, entry name, compression level)
. The compression level can be NoCompression
, Fastest
, or Optimal
. PowerShell 7 adds 'SmallestSize
. The entry name is how the file will be stored in the ZIP file.
