Weekend Scripter: Two Way-Cool PowerShell Text File Tricks: Tail and Wait

Weekend Scripter: Two Way-Cool PowerShell Text File Tricks: Tail and Wait

  • Comments 13
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, talks about two way-cool new Windows PowerShell parameters: Tail and Wait.

Microsoft Scripting Guy, Ed Wilson, is here. Some things in Windows PowerShell are just so cool that I get all carried away with them and lose focus on whatever I am supposed to be doing. It happens that way sometimes. Luckily, it is the weekend, so I am covered for frittering away my time. But hey, it is for a good cause.

Note  Today I talk about reading from a log file as it updates. I also talk about reading from the end of a log file. I am using the script I wrote yesterday to add to the log file as I watch for updates. See yesterday’s article, Weekend Scripter: Creating a Sample Log File by Using PowerShell, for that script and for a discussion of the script.

Reading x number of lines from beginning or from end of log

For log files that log to the end of the file, the most recent information is at the bottom of the file. This can be a problem if I don’t know how many lines of stuff are in the log. Oh, I can do it, but even using Windows PowerShell, it requires a bit of code. Not anymore, because we now have the tail parameter that will retrieve a specific number of lines from the very bottom of the file. This technique is shown here.

PS C:\> Get-Content -Path C:\fso\mylogfile.log -Tail 1

Added sample 125 at 4:0:42

PS C:\> Get-Content -Path C:\fso\mylogfile.log -Tail 2

Added sample 123 at 4:0:42

Added sample 125 at 4:0:42

PS C:\> Get-Content -Path C:\fso\mylogfile.log -Tail 3

Added sample 121 at 4:0:42

Added sample 123 at 4:0:42

Added sample 125 at 4:0:42

If I am interested in the first lines in the file, I use the –head parameter and specify how many lines I want to obtain. This is shown here.

PS C:\> Get-Content -Path C:\fso\mylogfile.log -Head 2

Added sample 0 at 3:46:40

Added sample 1 at 3:46:40

But what about when the action is still occurring?

If the action is still occurring, that is, it is still being written to the log file, use the –wait parameter of Get-Content. The command is shown here.

Get-Content -Path C:\fso\mylogfile.log -Tail 1 –Wait

In this way, I retrieve the last written log file entry as it occurs.

To test this, I run the command above in the Windows PowerShell console. The Windows PowerShell console waits for new lines to be written to the file. I then switch to the Windows PowerShell ISE and run my Add-LogV2.ps1 script so that new entries are added to the file.

I switch back to the Windows PowerShell console and watch the entries add new lines to the Windows PowerShell console. The result is shown in the following image.

Image of command output

Well, that is about it for monitoring a log file. Join me tomorrow when I will talk about parsing the System event log.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Ed,

    I do some logging in my domain at logon, logoff, and at different intervals...The data is stored in CSV format but the logging process fails if i have the CSV file open while it is stil being written to. Do you think there is something I can do with PS that might relay the information back in real-time? seems doable, and i wish i had the time to do it the right way. push me in the right direction if you can.


  • @brain

    Get-Content does not open the file exclusively. Like the tail command in *nix it is designed for monitoring logfiles.  If you are uisng VBScript to log to a CSV then the CSV file will be'tail'-able.  ZIf you are using some other mechanism that opens the file exclusivley like Excel then the file will not be viewable.

    If you are using Windows methods to log then the Get-Content 'shared/readonly' open method will not disrupt logging.  If youa re using ADO or ODBC to log then the file open might request 'exclusive' and it would fail.  'Exclusive' does not allow shared-read.  'shared-write' is allows a file to be opend shared-read. ADO allows us to choose the open method.

    Non-Windows utilities may not work correctly.

  • @Ed -

    You might note that this is PowerShell V3 only and that the 'head' is not documented. In PowerShell v2 only 'wait' is supported.

    'Tail' is documented as V3 only in some online docs.  'Head' is not documented.


    In V2 the -wait is very annoying because it spools the compete file before waiting.  On large logfiles this can be an issue.

  • @JRV thanks for pointing this out. You are right, of course!

  • @Ed

    I just love occasionally poking a bit of fun at Microsoft, especially PowerSHell.  It is so near perfect and yet the documentaion is all over the map.  There are so many undocumented features.  It is both cool and amusing.

  • Thanks, very useful. Is it possible to "tail" the Windows Event Log as well in some way?

  • Hi, I find that this method does not work if new data is appended to the log file (via a server). The powershell script just hangs and never prints it out to the new text to the screen. Advice?

  • Hi everybody.

    To tail text files in real time like the 'tail' Linux/Unix command, try this program:

  • i tried to use PS C:\> Get-Content -Path C:\fso\mylogfile.log -Tail 2 -Wait

    but it is not updating in real time, any solution for that

  • I was so excited to read about this tail like command that is native. I'm looking to take it one step further and write a script that will change color or insert line after each wait longer than x time. Any ideas?

  • This might be to ugly to post, but I did it. This will make the first line after a pause red. It specific to the date format of windowsupdate.log, but Im sure it could be modified to be more universal.
    Get-Content c:\windows\windowsupdate.log -Wait -Tail 100 | ForEach-Object { $culture = Get-Culture; $format = "yyyy-MM-dd HH:mm:ss:fff"; %{ $line=$_.split(" ");$datetime=$line[0,1]}; if ($a -eq "") {$a=[DateTime]::ParseExact($datetime,$format,$null)}; $b=$a; $a=[DateTime]::ParseExact($datetime,$format,$null); $dif=$a - $b; if ($dif -gt '00:05:00.0000000') {write-host -ForegroundColor red $line} Else {write-host $line}}

  • This one changes the color for each section of text. Its random so its get some very hard to read colors. There is a lot of room for improvement. Switching between two easy to read colors would be easier on the eyes.
    Get-Content c:\windows\windowsupdate.log -Wait -Tail 100 | ForEach-Object { $culture = Get-Culture; $format = "yyyy-MM-dd HH:mm:ss:fff"; %{ $line=$_.split(" ");$datetime=$line[0,1]}; if ($a -eq "") {$a=[DateTime]::ParseExact($datetime,$format,$null)}; $b=$a; $a=[DateTime]::ParseExact($datetime,$format,$null); $dif=$a - $b; if ($dif -gt '00:05:00.0000000') {$max = [System.ConsoleColor].GetFields().Count - 1; $color = [System.ConsoleColor](Get-Random -Min 0 -Max $max)}; write-host -ForegroundColor $color $line}

  • # https://support.microsoft.com/en-us/kb/902093
    #Color changes with changed caller identity

    # time lapsed statement inserted when time difference between lines is greater then $changethreshold's value

    $WSUSlogfile = "c:\windows\windowsupdate.log"
    $color = [System.ConsoleColor](13)
    $changethreshold = '00:05:00.0000000'
    $format = "yyyy-MM-dd HH:mm:ss:fff";

    $host.UI.RawUI.BufferSize = new-object System.Management.Automation.Host.Size(1024,50)

    Get-Content -path $WSUSlogfile -Wait -Tail 100 | ForEach-Object {%{ $line=$_.split(" ");$PIDTID=$line[2,3];$datetime=$line[0,1]}; if ($a -eq '') {$a=$PIDTID}; $b=$a; $a=$PIDTID; if ($adt -eq '') {$adt=[DateTime]::ParseExact($datetime,$format,$null)};$bdt=$adt; $adt=[DateTime]::ParseExact($datetime,$format,$null); $difdt=$adt - $bdt; if ($difdt -gt $changethreshold) {write-host -ForegroundColor DarkGray "----------------------------- $difdt lapsed -----------------------------------"}; if ("$b" -ne "$a") {if ($color -eq 'White') {$color = 'Yellow'} else {$color = 'White'}}; write-host -ForegroundColor $color $line}