How to zip / archive hidden files using Compress-Archive?
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
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.
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
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.