0
votes

How to read via Powershell a log file to get timestamp code error and message print it to the CSV file?

example: I have a file txt which contains:

2018-11-16 21:01:57, Info  DISM   DISM Package Manager: PID=5884
    TID=5844 Processing the top level command token(add-capability). -
    CPackageManagerCLIHandler::Private_ValidateCmdLine 

2018-11-16 21:05:32, Error  DISM   DISM Package Manager: PID=5884
    TID=5844 Failed processing package changes with session options
    -CDISMPackageManager::ProcessChangesWithOptions(hr:0x800704c7)

I want a report showing only for all errors with DateTime, code_error, message. I use the following regex:

 ^(0x8)[0-9a-f]{2,7} 

for searching the code error, but it doesn't work.

    $PathLogFile = $($PathFiles+$FileLog)
    $PathErrorFile =  $($PathFiles+$FileError)|
    
    $DataLog = $(Get-Content -Path $PathLogFile)

    foreach ($Line in $DataLog) {
        
            if (($Line -match '^(hr:0x)[0-9a-f]{2,8}?' ) -and ($Line.contains("Error") -and $Line.contains("Failed"))) {
                Write-Host $Line
            } 
    } 
2
Welcome to SO. If you haven't done yet you may take the Tour and read the help topic How to Ask before we proceed. Regardless of that - when you post code or error messsages or sample data you should format them as code so it keeps looking like the original. This way we can copy it easily and play around with it. Thanks in advance.Olaf
Please share the code you've tried so far, to show you've already put some effort into this on your own. Also, you may want to try Log Parser for reading logs.marsze
Please add additional information to your question - not as additional comments. Thanks. ... and BTW: is this the original formatting of the log file?Olaf
OK, we're improving ... ;-) ... again: is this the original format of the log file? does it really have line breaks in between the log entries and does it have empty lines? Is this your complete code? It should be PowerShell code as you added the PowerShell tag to your question. You may read the help topic minimal reproducible example as well. Make it easier for us to help you please. ;-)Olaf

2 Answers

3
votes

Here's my approach:

filter parse-log {
    param(
        [Parameter(Mandatory)]
        $Path
    )
    $entry = $null
    switch -regex -file $Path {
        # find start of entry, incl timestamp and log-level
        '^(?<timestamp>[\d\-]{10} [\d\:]{8}), (?<level>\w+) (?<message>.*)' {
            if ($entry) {
                # output
                $entry
            }
            $entry = [PSCustomObject]@{
                Timestamp = [DateTime]$Matches.timestamp
                Level = $Matches.level
                Message = $Matches.message
            }
        }
        "^\s+.*" {
            # append additional lines to the message
            $entry.Message += [Environment]::NewLine + $_.Trim()
        }
    }
    # output
    if ($entry) { $entry }
}

You could then use this function like this:

parse-log "c:\path\file.log" | where Level -eq Error 
1
votes

OK ... that's just the first try to answer your question as you did not answer my question in my comments yet. Assumed your log file looks a little more like others having one log entry per line you could start with something like this:

$LogEntries = @'
2018-11-16 21:01:57, Info  DISM   DISM Package Manager: PID=5884 TID=5844 Processing the top level command token(add-capability). - CPackageManagerCLIHandler::Private_ValidateCmdLine 
2018-11-16 21:05:32, Error  DISM   DISM Package Manager: PID=5884 TID=5844 Failed processing package changes with session options - CDISMPackageManager::ProcessChangesWithOptions(hr:0x800704c7)
'@ -split "`n"

foreach ($item in $LogEntries) {
    $item -match '(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}).*PID=(\d{4})' | Out-Null

    [PSCustomObject]@{
        Date = Get-Date $Matches[1]
        PID = $Matches[2]
    }
}

Try to run the code as it is to see what I mean.