Working with Compressed Files in PowerShell 5


Summary: Ed Wilson, Microsoft Scripting Guy, talks about the new compressed file cmdlets in Windows PowerShell 5.0 on Windows 10.

Microsoft Scripting Guy, Ed Wilson, is here. It finally happened. I ran out of Gunpowder Green tea over the weekend. I have been making lots of Gunpowder Green tea with hibiscus flowers, rose hips, lemon grass, and other combinations, and then chilling it down. It works great for the central Florida August afternoons (and indeed sometimes early morning and even late at night).

I still have lots of black tea, lots of herbs, and even a pound or so of Oolong tea. So I have decided I am going to use the Oolong tea to make iced tea. I know, I know. It seems like a sort of a waste, but the truth is that tea leaves will go bad—or at least they will lose their wonderful taste after about six months. That is why it is important to store them properly. Setting out the tea in a glass jar may look nice, but that is about the worst thing in the world you can do.

So, rather than let the Oolong tea go bad (or at least loose its wonderful flavor), I have decided to make probably the most expensive iced tea in the world. I will let you know how it goes. It is on my agenda for next week. I am thinking about Oolong tea, jasmine flowers, and lemon grass to start with. I have also ordered a ginger grater, and I might put a bit of ginger root in the tea. I will have to be really careful with my recipe though—otherwise I could end up ruining the taste of a nice bit of Oolong.

Yesterday in New Feature in PowerShell 5: Compress Files, I talked a little bit about finding and using the Compress-Archive cmdlet (function) in Windows PowerShell 5.0.

To be honest, I really don’t like the verbs, compress and expand, for these functions. I keep expecting it to be something like New-ZipFile. Even New-CompressedArchive would make sense because I really am creating a new archive (.zip file) and not compressing an archive. I am compressing files, but not really an archive. I am creating a new archive that happens to contain compressed files. Oh well, I can always create an alias if I want to. This technique is shown here:

New-Alias -Name New-ZipFile -Value Compress-Archive -Description "makes sense to me"

Note 
I do not recommend doing this too much because if you get used to always using New-ZipFile instead of Compress-Archive, you will end up using it in a script or somewhere your custom alias does not exist. If you can keep things straight, or if interoperability is a non-issue, you can create any alias and call things whatever you want.
On the other hand, this is a perfectly valid technique. Other Microsoft teams have introduced new aliases for old cmdlets (in the next release of the product) when it turns out the name they picked for their cmdlet "didn’t really work."
I was really annoyed when the new alias appeared on a certification exam. The cmdlet I had always used was the answer, but I did not notice that they added an alias—and therefore, I ended up guessing at the answer on the exam. I wrote a note at the end of the exam—for whatever good that might have done.

Compress multiple files to single archive

The Compress-Archive cmdlet accepts an array of strings for the file to compress. This means that I can supply an array of strings and compress them into a single archive. But the best way to do this is simply to pipe the results from the Get-ChildItem cmdlet to the Compress-Archive cmdlet and simply specify the destination.

This means that the Compress-Archive cmdlet immediately becomes incredibly flexible. Because I have written lots of posts about using Get-ChildItem to find all kinds of files, I can now simply use those commands and create single archives (.zip files) that contains all those well-filtered files. Here is a simple example where I archive all the text files in a single folder:

PS C:\> gci c:\fso\*.txt | Compress-Archive -DestinationPath c:\fso\myarchive.zip

PS C:\> gci C:\fso\myarchive.zip

    Directory: C:\fso

Mode                LastWriteTime         Length Name

----                -------------         ------ ----

-a----        8/10/2015  10:50 AM        1320793 myarchive.zip

What do I have in my archive?

Finding out what is in the archive can be as simple as navigating to the folder and opening it in Windows Explorer (as I did yesterday). But I can also use the .NET Framework to do this. Unfortunately, the assembly to do this is not loaded by default (although if working with .zip files is a regular requirement, I would definitely add the assembly to the profile).

I load the assembly, then use a static method to find out what is in the .zip file:

PS C:\> Add-Type -AssemblyName "system.io.compression.filesystem"

PS C:\> [io.compression.zipfile]::OpenRead("c:\fso\myarchive.zip").entries.name

A File with a `in the name.txt

AMoreComplete.txt

AnEmptyFile.txt

batteryReport.txt

ChangedMyFile.txt

connecttype.txt

CopyOfmyfile.txt

csidl.txt

decodedSimple.txt

decodeMOreComplete.txt

encodedSimple.txt

encodeMoreComplete.txt

epcisar.txt

mixed.txt

modload.txt

myfile.txt

myprocesses.txt

MyServiceStatus.txt

newfile.txt

process.txt

psreadline.txt

selectProcess.txt

Simple.txt

verbose.txt

What doesn’t work for verifying the contents of an archive?

Get-ChildItem –Recurse

Get-ChildItem –Force

Get-ChildItrem –Force –Recurse –Depth 10

These are shown here:

PS C:\> gci C:\fso\myarchive.zip -Recurse

    Directory: C:\fso

Mode                LastWriteTime         Length Name

----                -------------         ------ ----

-a----        8/10/2015  10:50 AM        1320793 myarchive.zip 

PS C:\> gci C:\fso\myarchive.zip -Recurse -Force

    Directory: C:\fso

Mode                LastWriteTime         Length Name

----                -------------         ------ ----

-a----        8/10/2015  10:50 AM        1320793 myarchive.zip

PS C:\> gci C:\fso\myarchive.zip -Recurse -Force -Depth 10

    Directory: C:\fso

Mode                LastWriteTime         Length Name

----                -------------         ------ ----

-a----        8/10/2015  10:50 AM        1320793 myarchive.zip

Expand a .zip file with Windows PowerShell 5.0

To expand a .zip file by using Windows PowerShell 5.0, I call the Expand-Archive cmdlet (function). I can specify a destination folder that does not exist. This is pretty cool. The command is shown here:

Expand-Archive C:\fso\myarchive.zip -DestinationPath c:\fso\expanded

When I have expanded the archive, I can then use Get-ChildItem to see what files are there. In this command, dir is an alias for Get-ChildItem:

PS C:\> dir C:\fso\expanded\

    Directory: C:\fso\expanded

Mode                LastWriteTime         Length Name

----                -------------         ------ ----

-a----        8/10/2015  11:20 AM             27 A File with a `in the name.txt

-a----        8/10/2015  11:20 AM            303 AMoreComplete.txt

-a----        8/10/2015  11:20 AM             77 AnEmptyFile.txt

<output truncated>

That is all there is to using the compression cmdlets. Join me tomorrow when I will talk about cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Comments (5)

  1. Anders P says:

    CreationTime, LastAccessTime and LastWriteTime are not preserved using Compress-Archive.
    If you think that matters, please vote for it here:
    https://connect.microsoft.com/PowerShell/Feedback/Details/1666542
    /Anders

  2. Stuart Fawcett says:

    Using 7Zip to test archive produced by the Compress-Archive command shows that there are no folders present ? - yet windows 7 & 10 does show the folders fine?

    Do you know why the built zip file does not represent the folders correctly?

    The command that produced the errant zip file was
    Compress-Archive -Path xxxxxxxxx -DestinationPath xxxxxxxxxx -Force -CompressionLevel Fastest

    Many thanks
    Stuart

  3. Josef M. says:

    Maybe I found a bug, strange behavior at least.

    When I want to compress my RELEASE (2GB) folder directly to the remote machine and ZIP archive doesn't exist there, I can use this without any problem:

    param
    (
    [string]$COMP_NAME = $(Read-Host "Enter VM's IP address"),
    [string]$DESTINATION = $(Read-Host "Select folder for ZIP archive")
    )

    Compress-Archive -Path .\RELEASE\* -DestinationPath \\$COMP_NAME\$DESTINATION -CompressionLevel Fastest

    But when I want to do same thing, archive already exists there and I will use Force parameter, the script will never finish and ZIP archive will be filled with it's content over and over again (0->800 MB, then 0->800 MB and again 0->800 MB etc.)

    Any ideas?

    P.S: I solved this problem with compressing the RELEASE folder to ZIP archive in the root folder (where script has been executed) and then moving the archive file to remote computer with PSDrive functionality, so it doesn't bother me anymore.

    1. Josef M. says:

      Sorry for my typo, this should be the right command:

      Compress-Archive -Path .\RELEASE\* -DestinationPath \\$COMP_NAME\$DESTINATION\release.zip -CompressionLevel Fastest

  4. drowa says:

    Why not an option to password protect the zip file?

Skip to main content