Link to home
Start Free TrialLog in
Avatar of Ken H.
Ken H.

asked on

Select Data From String array Using LINQ or Alternatives?

I need to write a conditional statement that pulls data from a log file and places it in table rows. What I need to get are all the lines that are not blank which reside between the following two lines in the log file (but only if the first line exists) and place them in a specific column (PrefIP) in the table.

[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]

[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols]
Dim Table1 As DataTable
        Table1 = New DataTable("SnapDrive")

        Dim Version As DataColumn = New DataColumn("Version")
        Version.DataType = System.Type.GetType("System.String")
        Table1.Columns.Add(Version)

        Dim PrefIP As DataColumn = New DataColumn("Preferred IP")
        PrefIP.DataType = System.Type.GetType("System.String")
        Table1.Columns.Add(PrefIP)

        Dim ServiceAcct As DataColumn = New DataColumn("Service Account")
        ServiceAcct.DataType = System.Type.GetType("System.String")
        Table1.Columns.Add(ServiceAcct)

        Dim sdVersionInfo As String() = IO.File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDriveVersionInfo.log")
        Dim sdRegistryData As String() = IO.File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDrive_RegistryInfo.log")

        Dim sdVersion As String = sdVersionInfo(16).Substring(93)  'These two lines are fine as they are located in static positions
        Dim sdService As String = sdRegistryData(20).Substring(26)
        Dim prefFlrIp = From q In versionInfoData Where q.Contains("Addresses") Select q.Split(" ")(1).Replace("[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]", String.Empty).Trim     

        Dim Row1 As DataRow
            Try
                Row1 = Table1.NewRow()
                Row1.Item(Version) = sdVersion
                Row1.Item(PrefIP) = If(prefFlrIp.Count > 0, prefFlrIp.First, "Not Set")
                Row1.Item(ServiceAcct) = sdService
                Table1.Rows.Add(Row1)
            Catch ex As Exception

            End Try

        gridSnapDriveProperties.DataSource = Table1
        gridSnapDriveProperties.DataBind()
    End Sub

Open in new window

Avatar of nepaluz
nepaluz
Flag of United Kingdom of Great Britain and Northern Ireland image

where do you declare versionInfoData? Is it the same as sdVersionInfo?
I have assumed they are one and the same. Here is a suggestion (a bit verbose and hopefully gets your result).
Dim ReqCK = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]"
Dim LastOC = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols]"
Dim prefFlrIp As New List(Of String)
If versionInfoData.Contains(ReqCK) Then
    Dim NewArray As New List(Of String)
    For Each x In versionInfoData
       If x = ReqCK Then Continue For
       If x = LastOC Then Exit For
       NewArray.Add(x)
    Next
    If NewArray.Count > 0 Then
       prefFlrIp = (From q In NewArray Where q.Contains("Addresses") Select q.Split(" ")(1)).ToList
    End If
End If

Open in new window

PS. You will need to assign a value to prefFlrIP in case ReqCK is not in your file.
Didn't we dix this question in https://www.experts-exchange.com/questions/27422267/Expression-Help.html ?

The text between the lines was extracted. The only thing you had to add is .trim() on the text and then to split it using the enter char to ne able to use it in the linq instruction.  
Avatar of Ken H.
Ken H.

ASKER

nepaluz - that code doesn't seem to be returning a value. Would you please review my code below for correctness?

djon - the code from that posts works when the encoding is UTF ... the log files are not UTF .... i don't actually know what they are, but I'm hoping to find a way to do this short of opening and saving the file as a new file with utf8 encoding and then reading from that file. I could not get that code to give me a value with the logs original formatting either.
Dim Table1 As DataTable
        Table1 = New DataTable("SnapDrive")

        Dim Version As DataColumn = New DataColumn("Version")
        Version.DataType = System.Type.GetType("System.String")
        Table1.Columns.Add(Version)

        Dim PrefIP As DataColumn = New DataColumn("Preferred IP")
        PrefIP.DataType = System.Type.GetType("System.String")
        Table1.Columns.Add(PrefIP)

        Dim ServiceAcct As DataColumn = New DataColumn("Service Account")
        ServiceAcct.DataType = System.Type.GetType("System.String")
        Table1.Columns.Add(ServiceAcct)

        Dim sdVersionInfo As String() = IO.File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDriveVersionInfo.log")
        Dim sdRegistryData As String() = IO.File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDrive_RegistryInfo.log")

        Dim ReqCK = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]"
        Dim LastOC = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols]"
        Dim prefFlrIp As New List(Of String)
        If sdRegistryData.Contains(ReqCK) Then
            Dim NewArray As New List(Of String)
            For Each x In sdRegistryData
                If x = ReqCK Then Continue For
                If x = LastOC Then Exit For
                NewArray.Add(x)
            Next
            If NewArray.Count > 0 Then
                prefFlrIp = (From q In NewArray Where q.Contains("Addresses") Select q.Split(" ")(1)).ToList
            End If
        End If

        Dim sdVersion As String = sdVersionInfo(16).Substring(93)
        Dim sdService As String = sdRegistryData(20).Substring(26)

        Dim Row1 As DataRow
        Try
            Row1 = Table1.NewRow()
            Row1.Item(Version) = sdVersion
            Row1.Item(PrefIP) = If(prefFlrIp.Count > 0, prefFlrIp.FirstOrDefault, "Not Set")
            Row1.Item(ServiceAcct) = sdService
            Table1.Rows.Add(Row1)
        Catch ex As Exception

        End Try

        Dim lineString As String = ""
        For Each line As String In sdRegistryData
            lineString &= line.ToString
            lineString &= vbCrLf
            txtOut.Text = lineString
        Next

        gridSnapDriveProperties.DataSource = Table1
        gridSnapDriveProperties.DataBind()
    End Sub

Open in new window

As this post, you can use powershell to automate encoding changing without knowing the incoming one.

http://superuser.com/questions/27060/batch-convert-files-for-encoding-or-line-ending/113682#113682
Your code looks OK. First port of call is make sure that the file contains all the data then place a line break in the code to find out what is in NewArray.
Avatar of Ken H.

ASKER

Nothing is in NewArray. It seems like the program thinks the string for ReqCK does not exist in the file, but it most certainly does.

I have another piece of code that reads the file into a textbox and both strings are present. Here is the output:

djon - I will take a look at that tonight. Thanks!


[SYSTEM\CurrentControlSet\Services\SWSvc]



			

Type			0x00000010 (16)

Start			0x00000002 (2)

ErrorControl			0x00000001 (1)

ImagePath			"C:\Program Files\NetApp\SnapDrive\SWSvc.exe"

DisplayName			SnapDrive

DependOnService0000001 (1)			RPCSS

ObjectName			NEWIMAGENT\snapx

Description			Manages and Monitors NetApp's SnapDrive



[SYSTEM\CurrentControlSet\Services\SWSvc\Licenses]



LPSM			



[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters]



WebServiceTCPPortNo			808

SupportedIBMProductIDs			Nseries

SupportedSCSIVendors			NETAPP;IBM



[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\DFMConfigParams]





[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\DFMConfigParams\ServerConfig]



Port			0x00000000 (0)

ServerName			

AdminUserNamex00000000			

Protocol			0x00000000 (0)



[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\HyperVConfig]





[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\HyperVConfig\ParentConfig]



ParentHostName			

TcpPort			0x00000328 (808)

Enable_Passthrough0328 (808)			0x00000000 (0)

IP			



[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]



FAS250-NI1			10.10.1.201

FAS250-NI2			10.10.1.203



[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols]





[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols\#!Default#!SSProtocol]



Position			0x00000000 (0)

Type			0x00000001 (1)

UserName			

Port			0x00000000 (0)



[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\VMwareEsx]



tracelevel			0x00000003 (3)

DbgLogFiles			0x00000064 (100)

DbgLogSize			0x01400103 (20971779)

Open in new window

OK, I have run the code and see what you are saying. Here is one that will populate the NewArray. However, the onlyoccurance of Addresses is in the required start string thus you still have nothing! Here goes, first declare sdRegistryData as:
Dim sdRegistryData = (From j In File.ReadAllLines(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "SnapDrive_RegistryInfo.log")) Where Not String.IsNullOrEmpty(j.Trim) Select j.Trim).ToList

Open in new window

I have added a Boolean check to start populating the NewArray to the routine, so you have:
Dim ReqCK = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]"
Dim LastOC = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols]"
Dim prefFlrIp As New List(Of String)
If sdRegistryData.Contains(ReqCK) Then
     Dim NewArray As New List(Of String), StartLog As Boolean = False
    For Each x In sdRegistryData
        If StartLog Then NewArray.Add(x)
        If x = ReqCK Then StartLog = True
        If x = LastOC Then Exit For
    Next
    If NewArray.Count > 0 Then
        prefFlrIp = (From q In NewArray Where q.Contains("Addresses") Select q.Split(" ")(1)).ToList
    End If
End If

Open in new window

Should be self explanatory, but what the code does is it will only start populating NewArray ONLY when it finds the required string and will exit the loop as soon as the end string is found. Additionally, I have introduced a check in populating sdRegistryData by removing ALL blank lines and triming all the strings so as to be able to find a match for the required strings.

Let me know how this works.
Hmmm, I left the path in the declaration of sdRegistryData as mine, you will have to change it back to:
Dim sdRegistryData = (From j In File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDrive_RegistryInfo.log") Where Not String.IsNullOrEmpty(j.Trim) Select j.Trim).ToList

Open in new window

There is still a problem with this line :
prefFlrIp = (From q In NewArray Where q.Contains("Addresses") Select q.Split(" ")(1)).ToList

The NewArray variable contains these lines :
FAS250-NI1                  10.10.1.201
FAS250-NI2                  10.10.1.203

q in the LINQ represents a line and none of these contains Addresses.

I would presume that this line works better :
prefFlrIp = (From q In NewArray Select q.Split(" ")(1)).ToList
Like I mentioned in my last suggestion, "the only occurance of Addresses is in the required start string thus you still have nothing!".  And yes, if it is the IP addresses that newimagent is looking to get, then the code will pick those up and
prefFlrIp = (From q In NewArray Select q.Split(" ")(1)).ToList

Open in new window

will get BOTH IPs into the list (with 10.10.1.201 being taken as the first)
Avatar of Ken H.

ASKER

You are right that was incorrect, but prefFlrIp = (From q In NewArray Select q.Split(" ")(1)).ToList does not return any value either.

Ideally though, I would like to get everthing on the lines between the two registry strings, so I would like to get both lines in full returned as below:

FAS250-NI1                  10.10.1.201
FAS250-NI2                  10.10.1.203
Then NewArray should already contained these lines.

If not, I presume it is still an encoding problem.
OK, I had to re-jig the code, this one does work (and no, its NOT an encoding issue)
prefFlrIp = (From q In NewArray Select q.Split(" ").Last).ToList

Open in new window

Can you also change the loop to
For Each x In sdRegistryData
    If x = LastOC Then Exit For
    If StartLog Then NewArray.Add(x)
    If x = ReqCK Then StartLog = True
Next

Open in new window

To get the lines in FULL, do a plain:
prefFlrIp = (From q In NewArray Select q).ToList

Open in new window

or even better, declare NewArray outside the If statement and it will contain both lines.
Avatar of Ken H.

ASKER

This still does not return a value. I've set breakpoints and there is no value in prefFlrIp.
Dim ReqCK = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]"
        Dim LastOC = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols]"
        Dim prefFlrIp As New List(Of String)

        If sdRegistryData.Contains(ReqCK) Then
            Dim NewArray As New List(Of String), StartLog As Boolean = False
            For Each x In sdRegistryData
                If x = LastOC Then Exit For
                If StartLog Then NewArray.Add(x)
                If x = ReqCK Then StartLog = True
            Next
            If NewArray.Count > 0 Then
                prefFlrIp = (From q In NewArray Select q).ToList
            End If
        End If

        Dim sdVersion As String = sdVersionInfo(16).Substring(93)
        Dim sdService As String = sdRegistryData(20).Substring(26)

        Dim Row1 As DataRow
        Try
            Row1 = Table1.NewRow()
            Row1.Item(Version) = sdVersion
            Row1.Item(PrefIP) = If(prefFlrIp.Count > 0, prefFlrIp.First, "Not Set")
            Row1.Item(ServiceAcct) = sdService
            Table1.Rows.Add(Row1)
        Catch ex As Exception

Open in new window

Strange! I get values for both preFlrIP (though this value is using the "old" iteration)
 User generated imageand NewArray
 User generated image
Avatar of Ken H.

ASKER

I must be missing something. Its as though that code is being skipped over.
Avatar of Ken H.

ASKER

I've attached my full code for this sub .... I have no idea why it's skipping the for loop, or why i'm not retrieving the data. Can you look at this and see if I'm somehow missing something?
Public Sub SnapDrive()
        If Directory.Exists(txtPath.Text & "\SnapDriveInfo\") Then

            Dim Table1 As DataTable
            Table1 = New DataTable("SnapDrive")

            Dim Version As DataColumn = New DataColumn("Version")
            Version.DataType = System.Type.GetType("System.String")
            Table1.Columns.Add(Version)

            Dim PrefIP As DataColumn = New DataColumn("Preferred IP")
            PrefIP.DataType = System.Type.GetType("System.String")
            Table1.Columns.Add(PrefIP)

            Dim ServiceAcct As DataColumn = New DataColumn("Service Account")
            ServiceAcct.DataType = System.Type.GetType("System.String")
            Table1.Columns.Add(ServiceAcct)

            Dim TBD1 As DataColumn = New DataColumn("TBD1")
            TBD1.DataType = System.Type.GetType("System.String")
            Table1.Columns.Add(TBD1)

            Dim TBD2 As DataColumn = New DataColumn("TBD2")
            TBD2.DataType = System.Type.GetType("System.String")
            Table1.Columns.Add(TBD2)

            Dim TBD3 As DataColumn = New DataColumn("TBD3")
            TBD3.DataType = System.Type.GetType("System.String")
            Table1.Columns.Add(TBD3)

            Dim TBD4 As DataColumn = New DataColumn("TBD4")
            TBD4.DataType = System.Type.GetType("System.String")
            Table1.Columns.Add(TBD4)

            Dim TBD5 As DataColumn = New DataColumn("TBD5")
            TBD5.DataType = System.Type.GetType("System.String")
            Table1.Columns.Add(TBD5)


            Dim sdVersionInfo As String() = IO.File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDriveVersionInfo.log")
            Dim sdRegistryData As String() = IO.File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDrive_RegistryInfo.log")

            Dim ReqCK = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]"
            Dim LastOC = "[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols]"
            Dim prefFlrIp As New List(Of String)

            If sdRegistryData.Contains(ReqCK) Then
                Dim NewArray As New List(Of String), StartLog As Boolean = False
                For Each x In sdRegistryData
                    If x = LastOC Then Exit For
                    If StartLog Then NewArray.Add(x)
                    If x = ReqCK Then StartLog = True
                Next
                If NewArray.Count > 0 Then
                    prefFlrIp = (From q In NewArray Select q).ToList
                End If
            End If

            Dim sdVersion As String = sdVersionInfo(16).Substring(93)
            Dim sdService As String = sdRegistryData(20).Substring(26)

            Dim Row1 As DataRow
            Try
                Row1 = Table1.NewRow()
                Row1.Item(Version) = sdVersion
                Row1.Item(PrefIP) = If(prefFlrIp.Count > 0, prefFlrIp.First, "Not Set")
                Row1.Item(ServiceAcct) = sdService
                Table1.Rows.Add(Row1)
            Catch ex As Exception

            End Try

            Dim lineString As String = ""
            For Each line As String In sdRegistryData
                lineString &= line.ToString
                lineString &= vbCrLf
                txtOut.Text = lineString
            Next

            gridSnapDriveProperties.DataSource = Table1
            gridSnapDriveProperties.DataBind()
        Else

        End If

    End Sub

Open in new window

nepaluz : From the past question, I had an encoding problem using the poster's file.

Could you test it using :
http://filedb.experts-exchange.com/incoming/2011/10_w44/518002/SnapDrive-RegistryInfo.log
Avatar of Ken H.

ASKER

So a couple of things. To put it to the right path I had to modify this line:

Dim sdRegistryData = (From j In File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDrive_RegistryInfo.log") Where Not String.IsNullOrEmpty(j.Trim) Select j.Trim).ToList

This line does collect data, and it looks like the statement removes all empty strings from the array, but when I step through this it only removes the first line in the file so the area between the two registry keys looks like:

"[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\PreferredFilerIPAddresses]"
" "
" "
" "
FAS250-NI1            10.10.1.201
" "
FAS250-NI2            10.10.1.203
" "
" "
" "
"[SYSTEM\CurrentControlSet\Services\SWSvc\Parameters\Protocols]"

Because of the spacing I cannot tell if the double quotes are "" or  " "
Avatar of Ken H.

ASKER

Arrrgh..... again it has to do with encoding. If i save the file as unicode it pulls the data. Is there a way i can on the fly convert the data to unicode as it's pulled into the array?
Hmm, turns out it is an encoding issue. What program creates your logs?
I'll repeat one of my previous comment.

------------------------------

As this post, you can use powershell to automate encoding changing without knowing the incoming one.

http://superuser.com/questions/27060/batch-convert-files-for-encoding-or-line-ending/113682#113682
what encoding is the file?
ASKER CERTIFIED SOLUTION
Avatar of nepaluz
nepaluz
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Strange, but if you look at line 2
Dim Converter = Encoding.Convert(Encoding.Unicode, Encoding.Unicode, IO.File.ReadAllBytes(filePath))

Open in new window

all I do is convert the file from Unicode to Unicode .... does not make sense but Ihave seen stranger things happen with code!
Avatar of Ken H.

ASKER

Its a program written by our engineering department. It's written in .NET but i'm not sure what any of the details are and I'm certain they won't change it so I'll have to work around it.

Yes as I said before djon thats a method of last resort at this point. I'm trying to wrap my head around all this filesystem io stuff mixed with LINQ. There is a point in the near future where I will need to run a server side executable against files to decode them, but I don't want to start down that road yet if i can avoid it.
Maybe you could try this out too.. Didn't test it (that time), but as it seems that Unicode reading is already supported.
Dim sdRegistryData As String() = IO.File.ReadAllLines(txtPath.Text & "\SnapDriveInfo\SnapDrive_RegistryInfo.log", System.Text.Encoding.Unicode)

Open in new window


To nepaluz : I presume that initial encoding is not Unicode, but probably another charset compatible with it. As most of the charset are compatible with the old ASCII-us charset.
actually, it works so well that if you change line 16 above to
prefFlrIp = (From q In NewArray Select q.Split(vbTab).Last).ToList

Open in new window

you get just the IP address (turns out it is delimited by a tab)
Avatar of Ken H.

ASKER

Thank you! This is exactly what I needed. How do you learn this stuff so well? I have been through my vb2010 and LINQ books and googled my butt off. Any suggestions as to what resources I should be using to learn this would be much appreciated.

I had to modify this to get what i was looking for but not much.

prefFlrIp = (From q In NewArray Select q).ToList

Open in new window


Again thank you both for so much help with this!
How do we learn this stuff I hear you ask? Well, as you can see,we got this at the first attempt, thats why I am a Guru or is that Wizard! As for resources, EE is a very good resource, I have found that I learn more helping answer questions / finding solutions to questions from other people. At the moment, I am working on several projects in VB that involve parsing lots of data (and I get to use LINQ a lot!) thus a natural selection to answer any queries that come in on that topic area.

The code you have resorted to above is actually redundant, remove the declaration of NewArray and replace it with prefFlrIp inside the loop. You end up with the same result!