0

I've been trying to wrap my head around this as I've attempted some solutions but could not get any of the work. Im currently trying to read a log file and input it into an array and then have it sort the array out into columns and the data underneath..

This is what I have so far:

$logFileArray = Get-Content -Path @("C:\Users\testuser\datatoparse.log")

foreach($item in $logFileArray)
{

    write-host $item
}

$logFileArray | Export-CSV -Path "logfile.csv" -NoTypeInformation

Pause

An example of what is in the log file.

1   IKE Peer: 192.168.8.188 (PHX2)
Type    : L2L             Role    : initiator 
Rekey   : no              State   : MM_ACTIVE 
Encrypt : 3des            Hash    : SHA       
Auth    : preshared       Lifetime: 86400
Lifetime Remaining: 52140

An example of what I want it to look like for the end result in the csv file

enter image description here

Any help or pointers would be much appreciated, thank you!

EDIT to show more example of the log file

1   IKE Peer: 192.168.8.188 (PHX2)
Type    : L2L             Role    : initiator 
Rekey   : no              State   : MM_ACTIVE 
Encrypt : 3des            Hash    : SHA       
Auth    : preshared       Lifetime: 86400
Lifetime Remaining: 52140
2   IKE Peer: 192.168.8.189 (Worcester)
Type    : L2L             Role    : initiator 
Rekey   : no              State   : MM_ACTIVE 
Encrypt : aes-256         Hash    : SHA       
Auth    : preshared       Lifetime: 28800
Lifetime Remaining: 5929
3   IKE Peer: 192.168.8.190 (Fresno)
Type    : L2L             Role    : initiator 
Rekey   : no              State   : MM_ACTIVE 
Encrypt : aes-256         Hash    : SHA       
Auth    : preshared       Lifetime: 28800
Lifetime Remaining: 6564
4   IKE Peer: 192.168.8.191 (San Leandro)
Type    : L2L             Role    : initiator 
Rekey   : no              State   : MM_ACTIVE 
Encrypt : 3des            Hash    : SHA       
Auth    : preshared       Lifetime: 86400
Lifetime Remaining: 71608
2
  • Can you post a few more sample of the data in the log files to I can see how they are separated? Commented Jun 9, 2023 at 14:14
  • I've edited to show more examples Commented Jun 9, 2023 at 14:36

3 Answers 3

2

Blerg. Already has some good-looking answers. Here's a variation using Switch.

Edited to use @mklement0 suggestion of -Regex for Switch

Get-Content -Path "[Path to Logfile]" |
    ForEach-Object {
        switch -Regex ($_) {
            '^(\d+)\s.*Peer:\s(\d+\.\d+\.\d+\.\d+.*\(.*\))$' {
                $ROW = [PSCustomObject]@{
                    Connection = $matches[1]
                    'IKE Peer' = $matches[2]
                }
            }
            '^([A-Z][\w\-_]+)[^\w]+([\w\-_]+)[^\w]+([\w\-_]+)[^\w]+([\w\-_]+)' {
                $ROW | Add-Member -NotePropertyName $matches[1] -NotePropertyValue $matches[2]
                $ROW | Add-Member -NotePropertyName $matches[3] -NotePropertyValue $matches[4]
            }
            '^Lifetime\sRemaining:\s+([0-9]+)$' {
                $ROW | Add-Member -NotePropertyName 'Lifetime Remaining' -NotePropertyValue $matches[1]
                $ROW | Select-Object -Property Connection,'IKE Peer',Type,Rekey,Encrypt,Auth,Role,State,Hash,Lifetime,'Lifetime Remaining' |
                    Export-Csv -Path "[Path to CSV]" -NoTypeInformation -Append
            }
        }
    }
Sign up to request clarification or add additional context in comments.

7 Comments

Hello, I wanted to try your code out as it does the export to csv function. When I attempted to use this It runs into an error saying: Add-Member : Cannot validate argument on parameter 'NotePropertyName'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
Also says this under that: Add-Member : Cannot add a member with the name "28" because a member with that name already exists. To overwrite the member anyway, add the Force parameter to your command.
Sorry. I only tested against the four entries you provided. This Regex may need to be tweaked ':.*:' if there are lines in your log with two colons that are not shown in your example.
@Grok42 No worries, where would you make this tweak at would it be at the { $_ -match ':.*:' } portion. I do not have anything with another colon but just increasing past a single digit in terms of connection. Like my data log file goes to 40 connections so the beginning number will expanded from a single digit to two digits. Thank you
Not sure why it's not exporting CSV content for you. Edited above to use @mklement's suggestion. Also moved Export-Csv within switch statement. Maybe give it a shot?
|
2

Not the prettiest but this regex seems to work for the provided example. The result looks as follows:

Connection IKEPeer                     Type Role      Rekey State     Encrypt Hash Auth      Lifetime
---------- -------                     ---- ----      ----- -----     ------- ---- ----      --------       
1          192.168.8.188 (PHX2)        L2L  initiator no    MM_ACTIVE 3des    SHA  preshared 86400
2          192.168.8.189 (Worcester)   L2L  initiator no    MM_ACTIVE aes-256 SHA  preshared 28800
3          192.168.8.190 (Fresno)      L2L  initiator no    MM_ACTIVE aes-256 SHA  preshared 28800
4          192.168.8.191 (San Leandro) L2L  initiator no    MM_ACTIVE 3des    SHA  preshared 86400

Regex details: https://regex101.com/r/fd6tNy/1

# Note the use of `-Raw` is mandatory here:
$content = Get-Content -Path "C:\Users\testuser\datatoparse.log" -Raw

$re = -join @(
    '(?ms)'
    '(?<Connection>^\d+)\s+IKE\sPeer[\s:]+(?<IKEPeer>[\d\.]+\s\([\w ]+\)).+?'
    'Type[\s:]+(?<Type>[\w]+)\s+Role[\s:]+(?<Role>\w+).+?'
    'Rekey[\s:]+(?<Rekey>\w+)\s+State[\s:]+(?<State>\w+).+?'
    'Encrypt[\s:]+(?<Encrypt>[\w-]+)\s+Hash[\s:]+(?<Hash>\w+).+?'
    'Auth[\s:]+(?<Auth>\w+)\s+Lifetime[\s:]+(?<Lifetime>\d+).+?'
    'Lifetime\sRemaining[\s:]+(?<LifetimeRemaining>\d+)'
) -as [regex]

$out = [ordered]@{}

$re.Matches($content) | ForEach-Object {
    $out.Clear()
    foreach($group in $_.Groups | Select-Object -Skip 1) {
        $out[$group.Name] = $group.Value
    }
    [pscustomobject] $out
} | Format-Table -AutoSize

2 Comments

When I went ahead and used this. my log file is around 40 connections and it actually skips some of the connections. The below answer was able to output every connection. It was very insightful to see how you attempted this question tho. Thank you so much :)
@JamieLovenduski i see, that's unfortunate. The regex in this answer is designed to match exactly what you provided in the answer and would fail if the input isn't exactly as shown in the question. I Should've made that clear my bad
0

Try following :

$filename = 'c:\temp\test.txt'

$reader = [System.IO.StreamReader]::new($filename)
$table = [System.Collections.ArrayList]::new()
$newRowPattern = '^(?<connection>\d+)\s+(?<key>[^:]+):(?<value>.*)'
$pattern = '^(?<key>[^:]+):(?<value>.*)'
While(($line = $reader.ReadLine()) -ne $null)
{
    $match = [regex]::match($line,$newRowPattern)

    if($Match.Success -eq $true)
    {
      $newRow = New-Object -TypeName psobject
      $newRow | Add-Member -NotePropertyName connection -NotePropertyValue $match.Groups['connection'].Value.Trim()
      $newRow | Add-Member -NotePropertyName $match.Groups['key'].Value.Trim() -NotePropertyValue $match.Groups['value'].Value.Trim()
      $table.Add($newRow)  | Out-Null
    } 
    else
    {
       $firstItem = $line.Substring(0,24)
       $match =[regex]::match($firstItem,$pattern)
       if($Match.Success -eq $true) { $newRow | Add-Member -NotePropertyName $match.Groups['key'].Value.Trim() -NotePropertyValue $match.Groups['value'].Value.Trim()}
       $secondItem = $line.Substring(24)
       $match =[regex]::match($secondItem,$pattern)
       if($Match.Success -eq $true) {$newRow | Add-Member -NotePropertyName $match.Groups['key'].Value.Trim() -NotePropertyValue $match.Groups['value'].Value.Trim()}

    }
}
$table | Format-List

Results :

connection         : 1
IKE Peer           : 192.168.8.188 (PHX2)
Type               : L2L
Role               : initiator
Rekey              : no
State              : MM_ACTIVE
Encrypt            : 3des
Hash               : SHA
Auth               : preshared
Lifetime           : 86400
Lifetime Remaining : 5214

connection         : 2
IKE Peer           : 192.168.8.189 (Worcester)
Type               : L2L
Role               : initiator
Rekey              : no
State              : MM_ACTIVE
Encrypt            : aes-256
Hash               : SHA
Auth               : preshared
Lifetime           : 28800
Lifetime Remaining : 5929

connection         : 3
IKE Peer           : 192.168.8.190 (Fresno)
Type               : L2L
Role               : initiator
Rekey              : no
State              : MM_ACTIVE
Encrypt            : aes-256
Hash               : SHA
Auth               : preshared
Lifetime           : 28800
Lifetime Remaining : 6564

connection         : 4
IKE Peer           : 192.168.8.191 (San Leandro)
Type               : L2L
Role               : initiator
Rekey              : no
State              : MM_ACTIVE
Encrypt            : 3des
Hash               : SHA
Auth               : preshared
Lifetime           : 86400
Lifetime Remaining : 7160

5 Comments

As previously discussed here and here, I am down-voting for unidiomatic PowerShell code that sets a bad example.
@mklement0 : You rather want the OP to use something that is not pretty and another solution that doesn't output the CSV. My code is simple and easy to understand and a simple Regex pattern that is self explanatory. My college professors would give you an F and I would get A+
My down-vote was unrelated to any other answers. Your code is the worst of both the following worlds, hence my vote: It combines unnecessarily low-level .NET API calls with unnecessarily verbose, inefficient, and outdated PowerShell techniques.
What you are then referring is Power Shell is superior to c#. Powershell is built on the same Net Library as c# and is not compiled. So c# is really more efficient than Powershell which is completely the opposite of what you are saying.
I said nothing about superiority and don't think that's a helpful perspective. PowerShell and C# are different languages (PowerShell is also a shell), with different purposes. Of course C#, as a compiled language, is faster, but how is that relevant? The point is that you're not writing PowerShell answers, you're writing C#-in-disguise answers, which misses out on most of what makes PowerShell PowerShell, as argued before in detail here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.