How, if at all, is it possible to add timestamps to each line of an output generated by the &
PowerShell operator?
Example:
PS H:\> $result = & ping 192.168.1.1 PS H:\> echo $result Pinging 192.168.1.1 with 32 bytes of data: Reply from 192.168.1.1: bytes=32 time=104ms TTL=250 Reply from 192.168.1.1: bytes=32 time=106ms TTL=250 Reply from 192.168.1.1: bytes=32 time=102ms TTL=250 Reply from 192.168.1.1: bytes=32 time=102ms TTL=250 Ping statistics for 192.168.1.1: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 102ms, Maximum = 106ms, Average = 103ms
Desired result:
PS H:\> echo $result 2014-12-08T14:45:48.8898125+00:00:Pinging 192.168.1.1 with 32 bytes of data: 2014-12-08T14:45:48.8932661+00:00:Reply from 192.168.1.1: bytes=32 time=104ms TTL=250 2014-12-08T14:45:48.9233451+00:00:Reply from 192.168.1.1: bytes=32 time=106ms TTL=250 2014-12-08T14:45:48.9765438+00:00:Reply from 192.168.1.1: bytes=32 time=102ms TTL=250 2014-12-08T14:45:49.0233105+00:00:Reply from 192.168.1.1: bytes=32 time=102ms TTL=250 2014-12-08T14:45:49.0233201+00:00: 2014-12-08T14:45:49.0238753+00:00:Ping statistics for 192.168.1.1: 2014-12-08T14:45:49.0239210+00:00: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), 2014-12-08T14:45:49.0233318+00:00:Approximate round trip times in milli-seconds: 2014-12-08T14:45:49.0237209+00:00: Minimum = 102ms, Maximum = 106ms, Average = 103ms
I know how to split / join a PowerShell array, but this can only happen AFTER the &
operator completes. I am looking for more realtime-like solution, where timestamps are added to the output while the & operator is running.
By the way, the timestamp itself is $($(Get-Date -Format o) + ":")
The $timestamp variable stores the results of a Get-Date command. Get-Date uses the Format parameter with the format specifier of lowercase o to create a timestamp String object. The object is sent down the pipeline to ForEach-Object . A ScriptBlock contains the $_ variable that represents the current pipeline object.
The $_ is a variable or also referred to as an operator in PowerShell that is used to retrieve only specific values from the field. It is piped with various cmdlets and used in the “Where” , “Where-Object“, and “ForEach-Object” clauses of the PowerShell.
You could use a filter:
filter timestamp {"$(Get-Date -Format o): $_"} $result = & ping 192.168.1.1 | timestamp
Sample output from $result
:
2014-12-08T11:42:59.2827202-05:00: 2014-12-08T11:42:59.2857205-05:00: Pinging 192.168.1.1 with 32 bytes of data: 2014-12-08T11:43:03.1241043-05:00: Request timed out. 2014-12-08T11:43:08.1236042-05:00: Request timed out. 2014-12-08T11:43:13.1241042-05:00: Request timed out. 2014-12-08T11:43:18.1246042-05:00: Request timed out. 2014-12-08T11:43:18.1246042-05:00: 2014-12-08T11:43:18.1246042-05:00: Ping statistics for 192.168.1.1: 2014-12-08T11:43:18.1246042-05:00: Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),
For anyone that is looking for more information on filter
, here is the documentation. It was surprising difficult to find since searching any combination of the word "filter" and "powershell" will give a million examples and no documentation. Also help filter
in powershell provides no obvious help either.
The answer provided by mjolinor is the best way to do something like this, but I wanted to expand on it.
filter timestamp {"$(Get-Date): $_"}
Is a shortcut for calling this
function timestamp { Process{"$(Get-Date): $_"} }
Both of these create named functions that accept input from the pipeline. Run help pipline
in powershell to learn more. The pipeline will operate on a single object at a time, and that object can be referred to with the automatic variable $_
. So each function will iterate over every item in the pipeline that was piped to it using the |
pipe character.
This behaves differently than a normal function in that it's working on the objects as they arrive, instead of all at once. For example running
function timestamp { "$(Get-Date): $input" } $result = & ping 127.0.0.1 $result | timestamp
Would dump the entire $result
object on a single line and result in a response that looks like this
03/14/2018 15:23:16: Pinging 127.0.0.1 with 32 bytes of data: Reply from 127.0.0.1: b ytes=32 time<1ms TTL=128 Reply from 127.0.0.1: bytes=32 time<1ms TTL=128 Reply from 12 7.0.0.1: bytes=32 time<1ms TTL=128 Reply from 127.0.0.1: bytes=32 time<1ms TTL=128 Pi ng statistics for 127.0.0.1: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 0ms, Avera ge = 0ms
Since the function is operating on the object as a whole you would have to iterate over each line. Changing it to this
function timestampfunction { foreach ($i in $input){ "$(Get-Date): $i" } }
Would give you the nicely formatted
03/14/2018 15:23:16: 03/14/2018 15:23:16: Pinging 127.0.0.1 with 32 bytes of data: 03/14/2018 15:23:16: Reply from 127.0.0.1: bytes=32 time<1ms TTL=128 03/14/2018 15:23:16: Reply from 127.0.0.1: bytes=32 time<1ms TTL=128 03/14/2018 15:23:16: Reply from 127.0.0.1: bytes=32 time<1ms TTL=128 03/14/2018 15:23:16: Reply from 127.0.0.1: bytes=32 time<1ms TTL=128 03/14/2018 15:23:16: 03/14/2018 15:23:16: Ping statistics for 127.0.0.1: 03/14/2018 15:23:16: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), 03/14/2018 15:23:16: Approximate round trip times in milli-seconds: 03/14/2018 15:23:16: Minimum = 0ms, Maximum = 0ms, Average = 0ms
Here is a nicely written article on the differences between these approaches.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With