Skip to content

Instantly share code, notes, and snippets.

@SteveGilham
Created September 22, 2026 20:49
Show Gist options
  • Select an option

  • Save SteveGilham/acbe98de6aa74f8adf4cb7e3a902bfca to your computer and use it in GitHub Desktop.

Select an option

Save SteveGilham/acbe98de6aa74f8adf4cb7e3a902bfca to your computer and use it in GitHub Desktop.
Set each zip entry's LastWriteTime to the zip file's LastWriteTime.
# 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