Parsing Text Logic

Welcome Forums General PowerShell Q&A Parsing Text Logic

This topic contains 5 replies, has 3 voices, and was last updated by

 
Participant
2 months ago.

  • Author
    Posts
  • #166783

    Participant
    Topics: 2
    Replies: 2
    Points: 15
    Rank: Member

    I'm hoping to get some help with a problem that has me stumped for the past few hours.  I'm trying to gather inventory information from a text string that looks like the following variable that is set to $SwitchInfo

    $SwitchInfo = 'Switch                      Type               Address          Model
    
    --------------------------- ------------------ ---------------- ---------------
    
    AMS01-FLEXE007-N2428-SW1(FOC2204M1KH) cluster-network 172.19.3.26 NX3132V
    
         Serial Number: Unknown
    
        Version Source: CDP
    
    AMS01-FLEXE007-N2428-SW2(FOC2204K1K7) cluster-network 172.19.3.27 NX3132V
    
         Serial Number: Unknown
    
        Version Source: CDP
    
    fcp-dst1p2s1(FDO22133NZM)   management-network 10.168.1.20      OTHER
    
         Serial Number: Unknown
    
        Version Source: CDP/ISDP
    
    fcp-dst1p2s2(FDO22133D8F)   management-network 10.168.1.21      OTHER
    
         Serial Number: Unknown
    
    vesw20-88732                cluster-network    10.33.99.168     CN1610
    
         Serial Number: 41014560299
    
        Version Source: ISDP
    
    vesw21-88732                cluster-network    10.33.99.169     CN1610
    
         Serial Number: 41011850242
    
        Version Source: ISDP'

    I need to gather Make, Model, Serial, and IP.  Since there is a difference between how Cisco and Brocade display their information, I'm not sure on the proper logic for this.  When I make it work for one, the other doesn't work.  Any help with this is greatly appreciated.  Here's what I have so far.

    Sorry for formatting, can't figure out how to get indents and color into code.

    Foreach($line in $SwitchInfo){
    If($line -like "*cluster-network*"){
    $SwitchName = ($($line -split "\s+")[0]).Split("(")[0]
    $SwitchIP = ($line -split "\s+")[2]
    $SwitchModel = ($line -split "\s+")[3]
    Switch ($SwitchModel) {
    'CN1610' {$SwitchMake = 'Brocade'}
    'NX3132V' {$SwitchMake = 'Cisco'}
    }
    #Temporarily Commented out Cisco Serial gathering to make Brocade side work
    #if($SwitchMake -eq 'Cisco') {
    #$SwitchSerial = ((($line -split "\s+")[0]).Split("(")[1]).split(")")[0]
    #}
    }
    elseif($line -like "*Serial Number:*"){ # -and $SwitchMake -eq 'Brocade'){ 
    $SwitchSerial = ($line -split "\s+")[3] 
    $Inventory += New-Object psobject -Property @{ 
    Count = 1
    ContractID = 'N/A'
    Status = 'Production'
    Name = $SwitchName;
    Function = 'Switch-CL'
    Make = $SwitchMake
    Model = $SwitchModel;
    Serial = $SwitchSerial;
    SiteID = $SiteCode
    LocationCode = $ClusterData.ClusterLocation
    ClusterMGMT_IP = $ClusterData.NcController.Address.IPAddressToString
    NodeMGMT_IP = $SwitchIP;
    NodeILO_IP = ''
    Environment = ''
    Purchaser = 'Flexential'
    Install_Date = Get-Date -format "MM/dd/yyyy"
    Vendor_EndDate = ''
    Notes = 'Auto Generated via Get-NTAPInventory' 
    }
    }
    }
  • #166915

    Participant
    Topics: 1
    Replies: 18
    Points: 64
    Rank: Member

    I find it easier to break up the information into records using a regular expression rather than examining line by line.  Then you can just extract the information you need from each record.  I hope this code sets you on the right path.

    • #166987

      Participant
      Topics: 2
      Replies: 2
      Points: 15
      Rank: Member

      Thank you very much, this method does appear to be much cleaner than how I was going about it.  That said, I'm still getting my bearings on Regex and don't fully understand the format.

      Can you explain what the following expressions mean:

      (?m)(?=^.+-network)

      Also, I understand the following grabs everything between parenthesis, but any chance you can break down what it's doing?

      \(([^)]+)\)

      Thanks again for your assistance with this, I have spent entirely way too much time trying to figure it out with "if" statements.

  • #166957

    Participant
    Topics: 2
    Replies: 2
    Points: 15
    Rank: Member

    Thank you very much, this method does appear to be much cleaner than how I was going about it.  That said, I'm still getting my bearings on Regex and don't fully understand the format.

    Can you explain what the following expressions mean:

    (?m)(?=^.+-network)

    Also, I understand the following grabs everything between parenthesis, but any chance you can break down what it's doing?

    \(([^)]+)\)

    Thanks again for your assistance with this, I have spent entirely way too much time trying to figure it out with "if" statements.

     

  • #166978

    Participant
    Topics: 2
    Replies: 483
    Points: 1,152
    Helping Hand
    Rank: Community Hero

    First one broken down:

    '(?m)(?=^.+-network)'
    
    (?m)     -- multi-line match mode. Don't think this is actually typically *needed* in PS, but it doesn't hurt to be explicit.
    (?=      -- Zero-length lookahead match (basically it means "match right before this thing specified between '(?=' and the closing parenthesis)
    ^        -- start of the string
    .+       -- period represents "any character", plus sign indicates one or more of the previous token; thus, "one or more of anything"
    -network -- all literal characters here, just match this text.

    Reference for multiline mode for you to read up on: https://www.w3schools.com/jsref/jsref_regexp_m.asp 🙂

    As for the second one:

    '\(([^)]+)\)'
    
    \(    -- escaped (literal) opening parenthesis
    (     -- start capture group
    [^)]+ -- match one or more characters that aren't a closing parenthesis
    )     -- end capture group
    \)    -- literal (escaped) closing parenthesis

     

    • #167029

      Participant
      Topics: 1
      Replies: 18
      Points: 64
      Rank: Member

      Thanks Joel, your explanation is pretty much spot on.

      The (?m) multiline option is required if you are trying to split a string with embedded newline characters (\r or \n).

      The .+ in the lookahead expression matches anything except an end of line (ie \r \n).  Using it is kind of sloppy because the regular expression engine will match anything up to the end of the line before it has to start backtracking one character at a time until it finds the -network.  Backtracking is inefficient. However, as the lines are unlikely to be too long, the backtracking is minimal and constrained by the first appearance of a newline. Even with a lot of records that shouldn't hurt performance too much.

      As an alternative to regular expressions you might also try the ConvertFrom-String cmdlet.  That allows you to take a template based approach to data extraction.  I haven't had much success with it, but to be honest I didn't persevere for very long either.  The learning curve for the cmdlet is probably easier than regular expressions.

       

You must be logged in to reply to this topic.