Skip to main content

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

Popular posts from this blog

Adding a Comment to a GPO with PowerShell

As I'm writing this article, I'm also writing a customization for a PowerShell course I'm teaching next week in Phoenix.  This customization deals with Group Policy and PowerShell.  For those of you who attend my classes may already know this, but I sit their and try to ask the questions to myself that others may ask as I present the material.  I finished up my customization a few hours ago and then I realized that I did not add in how to put a comment on a GPO.  This is a feature that many Group Policy Administrators may not be aware of. This past summer I attended a presentation at TechEd on Group Policy.  One organization in the crowd had over 5,000 Group Policies.  In an environment like that, the comment section can be priceless.  I always like to write in the comment section why I created the policy so I know its purpose next week after I've completed 50 other tasks and can't remember what I did 5 minutes ago. In the Group Policy module for PowerShell V3, th

Return duplicate values from a collection with PowerShell

If you have a collection of objects and you want to remove any duplicate items, it is fairly simple. # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   # Remove the duplicate values. $Set1 | Select-Object -Unique 1 2 3 4 5 6 7 What if you want only the duplicate values and nothing else? # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   #Create a second collection with duplicate values removed. $Set2 = $Set1 | Select-Object -Unique   # Return only the duplicate values. ( Compare-Object -ReferenceObject $Set2 -DifferenceObject $Set1 ) . InputObject | Select-Object – Unique 1 2 This works with objects as well as numbers.  The first command creates a collection with 2 duplicates of both 1 and 2.   The second command creates another collection with the duplicates filtered out.  The Compare-Object cmdlet will first find items that are diffe

How to list all the AD LDS instances on a server

AD LDS allows you to provide directory services to applications that are free of the confines of Active Directory.  To list all the AD LDS instances on a server, follow this procedure: Log into the server in question Open a command prompt. Type dsdbutil and press Enter Type List Instances and press Enter . You will receive a list of the instance name, both the LDAP and SSL port numbers, the location of the database, and its status.