Created
September 22, 2026 20:49
-
-
Save SteveGilham/acbe98de6aa74f8adf4cb7e3a902bfca to your computer and use it in GitHub Desktop.
Set each zip entry's LastWriteTime to the zip file's LastWriteTime.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Set each zip entry's LastWriteTime to the zip file's LastWriteTime. | |
| # Uses System.IO.Compression (.NET) APIs. | |
| # For post-processing the tool output from | |
| # - see https://x.com/m0n0works/status/2092085730839552016 | |
| # | |
| # Usage: | |
| # .\Set-ZipEntryTimesFromArchive.ps1 -Path 'C:\path\to\archive.zip' | |
| # Get-ChildItem *.zip | .\Set-ZipEntryTimesFromArchive.ps1 | |
| [CmdletBinding(SupportsShouldProcess = $true)] | |
| param( | |
| [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] | |
| [Alias('FullName')] | |
| [string]$Path, | |
| # After rewriting the zip, restore the archive file's own LastWriteTime | |
| # so updating entries does not bump the zip file timestamp to "now". | |
| [switch]$PreserveArchiveTimestamp = $true | |
| ) | |
| begin { | |
| Add-Type -AssemblyName System.IO.Compression | |
| Add-Type -AssemblyName System.IO.Compression.FileSystem | |
| } | |
| process { | |
| $zipPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path) | |
| if (-not (Test-Path -LiteralPath $zipPath -PathType Leaf)) { | |
| Write-Error "File not found: $zipPath" | |
| return | |
| } | |
| $archiveInfo = Get-Item -LiteralPath $zipPath | |
| $archiveLastWrite = $archiveInfo.LastWriteTime | |
| $archiveLastWriteUtc = $archiveInfo.LastWriteTimeUtc | |
| # Zip entries use DateTimeOffset. ZIP/DOS timestamps are typically | |
| # 2-second resolution and valid roughly 1980-01-01 through 2107-12-31. | |
| $entryTime = [DateTimeOffset]::new($archiveLastWrite) | |
| if (-not $PSCmdlet.ShouldProcess($zipPath, "Set all entry LastWriteTime values to $entryTime")) { | |
| return | |
| } | |
| $archive = $null | |
| try { | |
| $archive = [System.IO.Compression.ZipFile]::Open( | |
| $zipPath, | |
| [System.IO.Compression.ZipArchiveMode]::Update | |
| ) | |
| foreach ($entry in $archive.Entries) { | |
| # Directory entries are included; skip if you only want files: | |
| # if ($entry.FullName.EndsWith('/') -or $entry.FullName.EndsWith('\')) { continue } | |
| try { | |
| $entry.LastWriteTime = $entryTime | |
| } | |
| catch [System.ArgumentOutOfRangeException] { | |
| Write-Warning "Skipped '$($entry.FullName)': timestamp $entryTime is outside the ZIP-supported range." | |
| } | |
| } | |
| } | |
| finally { | |
| if ($null -ne $archive) { | |
| $archive.Dispose() | |
| } | |
| } | |
| if ($PreserveArchiveTimestamp) { | |
| [System.IO.File]::SetLastWriteTime($zipPath, $archiveLastWrite) | |
| [System.IO.File]::SetLastWriteTimeUtc($zipPath, $archiveLastWriteUtc) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment