Day 5: Turning Multi-line Text Based Logs into PowerShell
Objects.
Over the previous few days, we have been working to convert
a text based log file that contains one record per line into a PowerShell
object. Now we are going to take it to
the next level. As a Network Administrator, I have come across log
files that spread their information onto multiple lines. We are going to use the same set of steps as
before:
1.
Identify a rule to separate records
2.
Identify a rule to separate property names from
property values
3.
Create an object that contains all possible
property names.
4.
Read the log records into the object.
5.
Send to the pipeline.
We are going to build the cmdlet Import-MyLog2. We will be
using the txt file called Data2.txt,
which you can see below.
Log Example 2: Records on multiple lines with inconsistent
properties:
Server Blade #7 Information:
Server
Blade Type: No Server Blade Installed
Server Blade #8 Information:
Type:
Server Blade
Manufacturer: HP
Product
Name: ProLiant BL480c G1
Part
Number: 404707-B21
System
Board Spare Part Number: 438453-001
Serial
Number: 9999999999
UUID:
37343034-3730-4247-3837-999999999999
Server
Name: SRV000001
Asset Tag:
[Unknown]
ROM
Version: I14 10/25/2010
CPU 1:
Dual-Core Intel Xeon 3000 MHz
CPU 2:
Dual-Core Intel Xeon 3000 MHz
Memory: 49152 MB
Embedded
Ethernet
NIC 1:
00:19:BB:34:61:1C
NIC 2:
00:19:BB:34:41:24
NIC 3:
00:19:BB:29:92:37
NIC 4:
00:19:BB:29:92:38
iSCSI 1:
00:19:BB:34:61:1D
iSCSI 2:
00:19:BB:34:41:25
Mezzanine
2: QLogic QMH2462 4Gb FC HBA for HP c-Class BladeSystem
Port 1:
50:06:0b:00:00:6b:d3:9c
Port 2:
50:06:0b:00:00:6b:d3:9e
Management Processor Information:
Type: iLO2
Name:
SRV000001-i
Firmware Version: 2.12 Jul 16 2012
IP Address:
10.199.10.240
MAC
Address: 00:19:AA:34:21:99
Power
Management Controller Version: 0.5
Server Blade #9 Information:
Server
Blade Type: Bay Subsumed
Server Blade #10 Information:
Server
Blade Type: Bay Subsumed
Server Blade #11 Information:
Type:
Server Blade
Manufacturer: HP
Product
Name: ProLiant BL460c Gen8
Part
Number: 641016-B21
System
Board Spare Part Number: 719592-001
Serial Number: 9999999999
UUID:
30313436-3631-5A43-3332-99999999999
Server
Name: SRV0000002
Asset Tag:
[Unknown]
ROM
Version: I31 08/20/2012
CPU 1: Intel(R) Xeon(R) CPU E5-2609 0 @ 2.40GHz (4
cores)
CPU 2: Intel(R) Xeon(R) CPU E5-2609 0 @ 2.40GHz (4
cores)
Memory:
16384 MB
FLB Adapter
1: HP FlexFabric 10Gb 2-port 554FLB Adapter
Ethernet
FlexNIC (NIC 1) LOM1:1-a
6C:3B:E5:A9:DB:B0
Ethernet
FlexNIC (NIC 3) LOM1:1-b 6C:3B:E5:A9:DB:B1
Ethernet
FlexNIC (NIC 5) LOM1:1-c
6C:3B:E5:A9:DB:B2
Ethernet
FlexNIC (NIC 7) LOM1:1-d
6C:3B:E5:A9:DB:B3
Ethernet
FlexNIC (NIC 2) LOM1:2-a
6C:3B:E5:A9:DB:B4
Ethernet
FlexNIC (NIC 4) LOM1:2-b 6C:3B:E5:A9:DB:B5
Ethernet
FlexNIC (NIC 6) LOM1:2-c
6C:3B:E5:A9:DB:B6
Ethernet
FlexNIC (NIC 8) LOM1:2-d
6C:3B:E5:A9:DB:B7
This server
does not contain any mezzanine cards
Management Processor Information:
Type: iLO4
Name:
SRV0000002_i
Firmware
Version: 1.10 Jul 17 2012
IP Address:
20.199.8.40
MAC
Address: 10:61:4B:AD:C2:A7
Power
Management Controller Version: 3.0
We will be
reusing the function Get-Log without
any alterations from the previous code.
Please refer to day 2 if you need to brush up on this function.
We will also
use a Get-Records function, but this
time we have to deal with discovering when a record begins, and where it
ends. Let’s start by defining our rule
to determine the start of a record. I can see that a string of text “Server
Blade” is common at the start of all records. I also notice that records for Server Blade #9 and #10 also has a property field that
contains this pattern. To determine the
record start, I will have to use the patter “Server Blade #* Information:” to define each record.
Two other
items to note. The blade number is a
potential property that we will address when we create our custom
property. Also, there is an extra line
of nothing at the end of each record that we will want to filter out. At first you may be thinking that we can use
this black line as a delimiter between records.
Looking more carefully at the entire set of data, we see blank lines
between valid properties in the same object.
So, we will
create an object to send back to the calling statement with two
properties. The first is the index
number that starts a record and the second which is the index number of the
start of the next record minus 1. For
the last record, we will use the number of lines in the record to mark its end.
Function
Get-RecordIndex
{
Param ($Log)
# Determines
the index number of where each record starts and ends.
# Returns an
object with the start and end index number of
# each
record.
# Array
to hold all of the objects.
$Object
= @()
# Find
the start of each record.
For($X=0;$X -lt $Log.Count; $X++)
{
If($Log[$X] -like "Server
Blade #* Information:")
{
$Obj
= New-Object
-TypeName PSObject
$Obj
| Add-Member
-NotePropertyName "Start"
`
-NotePropertyValue $X
$Obj
| Add-Member
-NotePropertyName "End"
`
-NotePropertyValue
$Null
$Object
+= $Obj
}
} # End:
For($X=0;$X -lt $Log.Count; $X++)
# Derive
the end of each record.
For
($X = 0; $X -lt $Object.Count - 1; $X++)
{
$Object[$X].End = $Object[$X+1].Start -1
} # End:
For ($X = 0; $X -lt $Object.Count; $X++)
# Add the
final End value as the end of the log file.
$Object[$Object.count-1].End = $Log.count
# Return
the object to the calling statement.
Write-Output
$Object
} # End:
Function Get-RecordIndex
In the above
example, you can see the three stages that we need to go through to find the
index numbers of the start and end of each record. Each line of the log file is assigned an
index number starting with 0. The first
stage will find the start of each record.
Once the start is found, then an object is created with that index
number as the Start property and a Null value set as the End property. The next stage derives the End value from the
next records Start value. The third
stage will add the final objects End
value as the number of indexes in the log.
Tomorrow we
will look at how to derive our properties.
Comments