Parsing Text Logic

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'</pre>
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' 
}
}
}

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.

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.

 

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

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

 

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.

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.