Search code examples
loopspowershell-3.0

Powershell - How to select a block of text from a text based log file that has a time stamp in the log file entry


Sorry if the Title isn't very clear, I think part of my issue is I can't think of a way to clearly describe what I am trying to achieve, which has not helped me in 'Googling' anything that may be of help.

I am trying to create a generic script / function that I can pass 2 time values, a start time and an end time that will output all log file entries between these 2 time stamps. This will become the core part of a script to extract very small time spans of log file entries from logfiles that often exceed 1GB a day and are very difficult to manipulate in file viewers or editors efficiently and therefore take significant time to extract relevant dta from, for the purpose of providing developers with data to aid investigations into problems.

The log files are of differing formats but most of these follow the general format below:

2418 22:19:58: CTracker::ReadAvlPackets - ENTER ...
b18 22:19:58: SICInterfaceApp::ListenerRead: Qtype < 15> Subtype < 27> #8597208 From <¸i`      > 
b18 22:19:58: CTracker::OnListenerRead - PktPrc: 0x00000001
2418 22:20:00: cAvlComIMobile::GetData  - ErrSev: 0x00000000 
2418 22:20:02: cAvlComIMobile::GetData  - ErrSev: 0x00000000 

I have created a basic function:

function Get-LogExtract ($StartTime){
$Log = "path-to-log-file"
Get-Content $Log | 
ForEach-Object {
    $parts = $_ -split ' '
    if ($parts[1] -eq $StartTime) {
            $_
        }
    }
}

which if I run it using the following command line

Get-LogExtract 22:19:58:

it will output only the logfile lines that have the timestamp of 22:19:58: in the line, which is fine, it was what I initally wanted to achieve, but since this point the requirement has expanded.

What I now want to be able to do is to provide a start time and an end time and have all lines between these output.

I have tried to implement a do while loop to do this but was obvioulsy not getting anywhere as I couldn't achieve the goal I am trying to reach.

So I have a few questions.

    1. is there a better way to tackle what I am trying to achieve?
    2. if not, how can I implement a loop to achieve my goal?

Updated Code:

OK, so here's a code segment tweaked as advised by PSGuy below, which works a treat with logfiles that have a time stamp entry on every line.:

function Get-LogExtract ($StartTime, $EndTime) {
$Log = "path-to-log-file"
Get-Content $Log | 
    ForEach {
    $parts = $_ -split ' '
        if ($parts[1] -ge $StartTime -and $parts[1] -le $EndTime) {
            $_
        }
    }
}

Solution

  • There are a few things you can do here. The first is, if you want a true date-time object, then you can run the following static method of the System.DateTime class:

    [DateTime]::Parse($Time) # 22:19:58 == Friday, September 19, 2014 10:19:58 PM
    

    You can also do string comparisons, because any comparison operator against a string will evaluate each character by Char value, so "22:19:59" -gt "22:19:58" is true.

    I think that converting to a DateTime format will be easier for you, however, doing a simple string comparison will work. Something like:

    If $line[$I] -ge "22:19:59" -and $line[$I] -le "23:59:59" will theoretically work in your proposed script / function. I would also recommend doing a for loop to step through each line of the log file, however, it's not required. I'm not a big fan of the foreach-object cmdlet if I'm not using actual objects in the pipleline, where I can call a static method against the object itself. Here, it's just simple string work, and I would personally use a for loop, but it's all a matter of preference. The for construct would look like this:

    $logFile = Get-Content myLogFile.log # or whatever file format, it's an input arg anyway
    for ($I = 0; $I -le $logFile.GetUpperBound(""); $I++)
    {
        $logFile[$I] # reads the line; you can assign a variable at this point
    }
    

    A foreach loop would also work. I personally like using for, but foreach is effectively the same thing. The foreach equivalent is:

    foreach ($line in $logFile)
    {
        $line # perform whatever split operations you want to perform
    }
    

    Please let us know if it works!