Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Tuesday, June 18, 2013

Using Text Based Logs with Windows PowerShell (5 of 8)

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:
        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:
        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.

No comments: