15

When zipping folders using Compress-Archive it skips all hidden files.

The Documentation page tells us that this cmdlet uses Microsoft .NET Framework API System.IO.Compression.ZipArchive in the background.

Is there some way to force it to archive hidden files? I cannot find this issue documented anywhere. I tried -Force for the heck of it, didn't help.

My current workaround is to use Set-FileAttribute to remove the hidden attribute before zipping.

Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
GuidedHacking
  • 3,628
  • 1
  • 9
  • 59
  • 2
    I thought `Get-ChildItem -Path '...' -Force | Compress-Archive -DestinationPath '...'` would be the solution, but that throws a `Get-Item : Could not find item ...` error with the path of one of the hidden files. – Lance U. Matthews Nov 30 '18 at 05:05
  • Thought adding the force parameter to Compress-Archive would fix this too, same errors using `Compress-Archive $test.fullname -Force -DestinationPath test.zip` – Owain Esau Nov 30 '18 at 05:26

4 Answers4

7

This looks like a bug/oversight in the Compress-Archive cmdlet. Since the cmdlet provides no "include hidden files" parameter but does accept a collection of source files via the -Path or -LiteralPath parameters, I would expect either this...

Compress-Archive -Path (
    Get-ChildItem -Path '...' -Force `
        | Select-Object -ExpandProperty 'FullName' `
) -DestinationPath '...'

...or this...

Get-ChildItem -Path '...' -Force | Compress-Archive -DestinationPath '...'

...to work as a way of passing hidden files to the cmdlet; the key being specifying the -Force parameter for Get-ChildItem. Both of those invocations, however, throw these errors...

Get-Item : Could not find item ....
At C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:814 char:63
+ ... Entry.LastWriteTime = (Get-Item -LiteralPath $currentFilePath).LastWr ...
+                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (...:String) [Get-Item], IOException
    + FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetItemCommand

Exception setting "LastWriteTime": "Cannot convert null to type "System.DateTimeOffset"."
At C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:814 char:25
+ ...             $currentArchiveEntry.LastWriteTime = (Get-Item -LiteralPa ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenSetting

...for the first hidden file in the input list. (Note that invoking the first snippet without Select-Object -ExpandProperty 'FullName' instead throws Compress-Archive : The path '...' either does not exist or is not a valid file system path..)

On my system, the referenced lines 812-814 of Microsoft.PowerShell.Archive.psm1 are...

# Updating  the File Creation time so that the same timestamp would be retained after expanding the compressed file. 
# At this point we are sure that Get-ChildItem would succeed.
$currentArchiveEntry.LastWriteTime = (Get-Item -LiteralPath $currentFilePath).LastWriteTime

So, even if we pass -Force to Get-ChildItem to get the paths of hidden file objects to pass to Compress-Archive, internally the cmdlet is fetching those file objects again using Get-Item...but it's not passing -Force, which of course will fail (despite what the comment on the previous line claims). Thus, I don't think there's any way to get Compress-Archive to work with hidden files without either you or Microsoft editing that script.

Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
4

I replaced Compress-Archive with \[System.IO.Compression.ZipFile]::CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName) and found (on macOS at least) that the ZIP-file included a directory that starts with . (which is one way to hide a directory/file on macOS). This is using PowerShell 7.2.

Michiel van Oosterhout
  • 22,839
  • 15
  • 90
  • 132
  • 1
    I've tested using [system.io.compression.zipfileextensions.createentryfromfile](https://docs.microsoft.com/en-us/dotnet/api/system.io.compression.zipfileextensions.createentryfromfile?view=net-6.0) on Windows and it compressed hidden files, as long as you use the `-Force` parameter to `Get-ChildItem` so it finds the files. In my tests the hidden attribute was not preserved in the archive. See [this answer](https://stackoverflow.com/questions/70171826/archive-folder-without-some-subfolders-and-files-using-powershell/70173927#70173927) for an example that stores a path in the archive. – Rich Moss Jan 10 '22 at 20:38
  • I can confirm that this works on OSX/PS7 and this is an excellent workaround until `Compress-Archive` is updated to handle hidden files. – Hobadee Mar 18 '22 at 04:57
3

I've just had the same issue and this is how I got aroung it

# WARNING: This only works on a windows based powershell core terminal instance.
# In a linux based powershell core instance the .dot files are not included in 
# the final archive when using the -Filter example

# This will include .files like .gitignore
Get-ChildItem -Path . -Filter *.* | Compress-Archive -DestinationPath dist.zip

# This will include .dot files like .gitignore and any that are hidden like .git
Get-ChildItem -Path . -Force | Compress-Archive -DestinationPath dist.zip
Pr1nz
  • 91
  • 5
1

Well ...that's really annoying then! I've taken to using 7-Zip via Powershell but of course that does mean I'm using yet another tool. It also means it's almost redundant using Compress-Archive.

Here's part of my script delcaring the 7Zip variables and zipping stuff:

    $7ZipPath = "$env:ProgramFiles\7-Zip\7z.exe"
    
    If (-Not (Test-Path -Path $7ZipPath -PathType Leaf)) {
        throw "7 Zip File '$7ZipPath' Not Found"
    PAUSE
    }
    
    Set-Alias 7Zip $7ZipPath 
    
    $ItemsToZip = @{
    Path= "$TempDirectory\*"
    CompressionLevel = "Fastest"
    DestinationPath = $MyZipFile
    
    Compress-Archive @ItemsToZip
    
    7zip u $MyZipFile -ux2y2z2 "C:\Path\HiddenFile.ext"

Hope that helps someone

Andy Pyne
  • 37
  • 3