The universal decoder
terminal / powershell
function ConvertFrom-FileTimeBytes {
param([byte[]] $Bytes, [int] $Offset = 0)
if ($Bytes.Length -lt $Offset + 8) { return $null } # short blob: declare, don't crash
$raw = [BitConverter]::ToInt64($Bytes, $Offset)
if ($raw -le 0) { return $null } # 0/-1 = sentinel, not a date
[DateTime]::FromFileTimeUtc($raw).ToLocalTime()
}Rules that keep it honest
- Length check first. Real-world approval blobs come in 4, 8 and 12-byte flavors. Decoding byte offsets blindly is how quick scripts die with IndexOutOfRange.
- Zero is not 1601. A FILETIME of 0 isn't “the epoch”; it means “no date stored here.” Render it as
—, not a maximum-range exception. - Convert to local after constructing UTC. FILETIME columns are UTC;
FromFileTimeUtc(..).ToLocalTime()is the only two-step that's always right around DST changes.
Use it for StartupApproved blobs (bytes 4–11), event-log binary payloads, or WMI datetime fields. One decoder — never re-implement byte-shuffling per script again.