Last active
September 30, 2024 20:53
-
-
Save sba923/bc52cf74197ab3cddce825e8b502e28b to your computer and use it in GitHub Desktop.
Improvement on Export-Csv that includes milliseconds in DateTime properties
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
#requires -version 7.3 | |
# this is one of Stéphane BARIZIEN's public domain scripts | |
# the most recent version can be found at: | |
# https://gist.github.com/sba923/bc52cf74197ab3cddce825e8b502e28b#file-export-csvwithmilliseconds-ps1 | |
<# | |
.SYNOPSIS | |
Proxy for Export-Csv that adds milliseconds to DateTime properties | |
.DESCRIPTION | |
When objects contain properties of type DateTime, Export-Csv doesn't include milliseconds in the resulting CSV file: | |
[PSCustomObject]@{ | |
Date = [datetime]"2024-12-31 23:59:59.999" | |
} | Export-Csv foo.csv | |
Get-Content foo.csv | |
"Date" | |
"2024-12-31 23:59:59" | |
This proxy script adds milliseconds to the resulting CSV: | |
[PSCustomObject]@{ | |
Date = [datetime]"2024-12-31 23:59:59.999" | |
> } | Export-CsvWithMilliseconds.ps1 foo.csv | |
> Get-Content foo.csv | |
"Date" | |
"2024-12-31 23:59:59.999" | |
Until https://github.com/PowerShell/PowerShell/issues/19536 is addressed, this is an acceptable workaround. | |
#> | |
# original proxy code produced by: | |
# $MetaData = New-Object System.Management.Automation.CommandMetaData (Get-Command Export-Csv) | |
# [System.Management.Automation.ProxyCommand]::Create($MetaData) | |
[CmdletBinding(DefaultParameterSetName = 'Delimiter', SupportsShouldProcess = $true, ConfirmImpact = 'Medium', HelpUri = 'https://go.microsoft.com/fwlink/?LinkID=2096608')] | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] | |
[psobject] | |
${InputObject}, | |
[Parameter(Position = 0)] | |
[ValidateNotNullOrEmpty()] | |
[string] | |
${Path}, | |
[Alias('PSPath', 'LP')] | |
[ValidateNotNullOrEmpty()] | |
[string] | |
${LiteralPath}, | |
[switch] | |
${Force}, | |
[Alias('NoOverwrite')] | |
[switch] | |
${NoClobber}, | |
[ValidateNotNullOrEmpty()] | |
# remove typing, see https://github.com/PowerShell/PowerShell/issues/19647 | |
${Encoding}, | |
[switch] | |
${Append}, | |
[Parameter(ParameterSetName = 'Delimiter', Position = 1)] | |
[ValidateNotNull()] | |
[char] | |
${Delimiter}, | |
[Parameter(ParameterSetName = 'UseCulture')] | |
[switch] | |
${UseCulture}, | |
[Alias('ITI')] | |
[switch] | |
${IncludeTypeInformation}, | |
[Alias('NTI')] | |
[switch] | |
${NoTypeInformation}, | |
[Alias('QF')] | |
[string[]] | |
${QuoteFields}, | |
[Alias('UQ')] | |
[Microsoft.PowerShell.Commands.BaseCsvWritingCommand+QuoteKind] | |
${UseQuotes}) | |
begin | |
{ | |
# derived from https://github.com/PowerShell/PowerShell/issues/19536#issuecomment-1515140128 | |
# Save the original culture. | |
$original = [cultureinfo]::CurrentCulture | |
# Temporarily replace it with a read/write copy. | |
[cultureinfo]::CurrentCulture = [cultureinfo] $original.Name | |
# Modify the LongTimePattern format to include milliseconds. | |
[cultureinfo]::CurrentCulture.DateTimeFormat.LongTimePattern += ([cultureinfo]::CurrentCulture.NumberFormat.CurrencyDecimalSeparator + 'fff') | |
# Now .ToString(), which uses ShortDatePattern and LongTimePattern, | |
# separated by a space, uses the modified formats. | |
try | |
{ | |
# removed according to https://github.com/PowerShell/PowerShell/issues/10863 | |
# $outBuffer = $null | |
# if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) | |
# { | |
# $PSBoundParameters['OutBuffer'] = 1 | |
# } | |
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\Export-Csv', [System.Management.Automation.CommandTypes]::Cmdlet) | |
$scriptCmd = { & $wrappedCmd @PSBoundParameters } | |
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin) | |
$steppablePipeline.Begin($PSCmdlet) | |
} | |
catch | |
{ | |
# changed according to https://github.com/PowerShell/PowerShell/issues/10863#issuecomment-545533276 | |
# throw | |
$PSCmdlet.ThrowTerminatingError($_) | |
} | |
} | |
process | |
{ | |
try | |
{ | |
$steppablePipeline.Process($_) | |
} | |
catch | |
{ | |
# changed according to https://github.com/PowerShell/PowerShell/issues/10863#issuecomment-545533276 | |
# throw | |
$PSCmdlet.ThrowTerminatingError($_) | |
} | |
} | |
end | |
{ | |
try | |
{ | |
$steppablePipeline.End() | |
} | |
catch | |
{ | |
# changed according to https://github.com/PowerShell/PowerShell/issues/10863#issuecomment-545533276 | |
# throw | |
$PSCmdlet.ThrowTerminatingError($_) | |
} | |
} | |
clean | |
{ | |
# Restore culture | |
[cultureinfo]::CurrentCulture = $original | |
if ($null -ne $steppablePipeline) | |
{ | |
$steppablePipeline.Clean() | |
} | |
} | |
<# | |
.ForwardHelpTargetName Microsoft.PowerShell.Utility\Export-Csv | |
.ForwardHelpCategory Cmdlet | |
#> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Your workarounds for timestamps with Export-Csv just saved me a ton of time today. Thanks!
Just wanted to let you know that it doesn't work in all cultures to add the milliseconds at the end. In my case,
LongTimePattern
ish:mm:ss tt
(tt is AM/PM, so I would get something like4/10/1997 10:51:36 PM.000
). I ended up using:Didn't get a chance to thoroughly test that but it did what I needed for today. (In my case had to go down to 100 ns because I was dealing with file times.)