VB.NET - Return more than one result from code

I have a bit of VB.NET code that can search through Active Directory looking in the computer description field for a username. This is fine as it will return the computer name that they are or have logged on to. The problem is if it it matches more than one computer it just returns "X computers found".

Not being all that great with code I'm kind of stuck with how to achieve this. Would appreciate any help.

Try

                Application.DoEvents()

                Using searcher As New DirectorySearcher("(&(objectClass=computer))")
                    searcher.PropertiesToLoad.Add("name")
                    searcher.PropertiesToLoad.Add("description")
                    Dim computers = (From computer As SearchResult In searcher.FindAll()
                           Let entry = computer.GetDirectoryEntry()
                           Where Not String.IsNullOrEmpty(entry.Properties("description").Value) _
                           AndAlso entry.Properties("description").Value.ToString().IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1
                           Select New With {.Name = CType(entry.Properties("name").Value, String), .Description = CType(entry.Properties("description").Value, String)})

                    If computers.Count = 0 Then
                        txtHostName.Text = "No Results"
                    ElseIf computers.Count > 1 Then
                        For Each computer In
                            txtHostName.Text = computers.First().Name
                        Next

                        'txtHostName.Text = String.Format("{0} computers Found", computers.Count)
                    Else
                            txtHostName.Text = computers.First().Name
                    End If
                    Return computers.Select(Function(x) x.Name)
                End Using
            Catch ex As Exception

Open in new window


What I'm hoping to do is get it to open in a separate window where you can choose which PC you want to get more information on which then goes into the txtHostName.Text field.
LVL 2
fruitloopyAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Fernando SotoRetiredCommented:
Hi fruitloopy;

The following should be all you need

These lines of code will search the Active Directory and return all of the information asked for.
Dim computers = (From computer As SearchResult In searcher.FindAll()
       Let entry = computer.GetDirectoryEntry()
       Where Not String.IsNullOrEmpty(entry.Properties("description").Value) _
       AndAlso entry.Properties("description").Value.ToString().IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1
       Select New With {.Name = CType(entry.Properties("name").Value, String), .Description = CType(entry.Properties("description").Value, String)})

Open in new window


This is the code section that will need to be changed to do what you want.
If computers.Count = 0 Then                                                              
    txtHostName.Text = "No Results"                                                      
ElseIf computers.Count > 1 Then                                                          
    For Each computer In                                                                 
        txtHostName.Text = computers.First().Name                                        
    Next                                                                                 
                                                                                         
    'txtHostName.Text = String.Format("{0} computers Found", computers.Count)            
Else                                                                                     
        txtHostName.Text = computers.First().Name                                        
End If

Open in new window

This code should replace the above code
If computers.Count = 0 Then
    txtHostName.Text = "No Results"
ElseIf computers.Count > 1 Then
    Dim names = computers.Select(Function(x) x.Name).ToList()
    Dim selectForm As New SelectComputer()
    selectForm.NameList = names
    If selectForm.ShowDialog(Me) = DialogResult.OK Then
        txtHostName.Text = selectForm.selectedName
    Else
        txtHostName.Text = "No Results"
    End If
    selectForm.Dispose()
Else
    txtHostName.Text = computers.First().Name
End If

Open in new window

And to use the replacement code above you need to create a custom dialog box that contains 1 ListBox and two buttons with the following code.
Public Class SelectComputer

    Public NameList As New List(Of String)
    Public selectedName As String = "No Results"


    Private Sub BtnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
        If ListBox1.SelectedItem IsNot Nothing AndAlso Not String.IsNullOrEmpty(ListBox1.SelectedItem.ToString) Then
            selectedName = ListBox1.SelectedItem.ToString()
        End If

        Me.DialogResult = DialogResult.OK
    End Sub

    Private Sub BtnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        Me.DialogResult = DialogResult.Cancel
    End Sub

    Private Sub SelectComputer_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ListBox1.Items.Insert(0, "No Results")
        ListBox1.Items.AddRange(NameList.ToArray)
    End Sub
End Class

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
fruitloopyAuthor Commented:
Fantastic bit of code.

One issue though:

When I select one of the entries in the SelectComputer form and click the BtnOK it returns "No Results" in txtHostName.Text field.

I cant figure out why
0
Fernando SotoRetiredCommented:
You should only be selecting one item from the ListBox before clicking the OK button.
0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

fruitloopyAuthor Commented:
Yeah that's what I'm doing. I'm only selecting one entry but now since I commented out the
Else
                            'txtHostName.Text = "No Results"
                        End If

Open in new window

it doesnt put anything in the txtHostName.Text field.

See attached2018-02-08-13_57_34.png
0
fruitloopyAuthor Commented:
If I uncomment out the line aboev it returns "No Results" in the txtHostName.Text field again. It's as if it's ignoring the  DialogResult.OK from the SelectComputer Form
0
fruitloopyAuthor Commented:
Fixed it but had to make the following changes:

SlectedComputer Form
Public Class SelectComputer

    Public NameList As New List(Of String)
    Public selectedName As String = "No Results"

    Private Property DialogResult As Windows.Forms.DialogResult


    Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
        If ListBox1.SelectedItem IsNot Nothing AndAlso Not String.IsNullOrEmpty(ListBox1.SelectedItem.ToString) Then
            selectedName = ListBox1.SelectedItem.ToString()
            Main.txtHostName.Text = selectedName
        End If

        Me.DialogResult = DialogResult.OK
        Me.Close()
    End Sub

    Private Sub BtnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        Me.DialogResult = DialogResult.Cancel
        Me.Close()
    End Sub

    Private Sub SelectComputer_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ListBox1.Items.Insert(0, "Select one:")
        ListBox1.Items.AddRange(NameList.ToArray)
    End Sub
End Class

Open in new window


Main Form
If computers.Count = 0 Then
                        txtHostName.Text = "No Results"
                    ElseIf computers.Count > 1 Then
                        Dim names = computers.Select(Function(x) x.Name).ToList()
                        Dim selectForm As New SelectComputer()
                        selectForm.NameList = names
                        If selectForm.ShowDialog(Me) = DialogResult.OK Then
                            txtHostName.Text = selectForm.selectedName
                        Else
                            'txtHostName.Text = "No Results"
                        End If
                        selectForm.Dispose()

Open in new window


I added Main.txtHostName.Text = selectedName to the SelectComputers form and commented out the Else txtHostName.Text = "No Results". Not sure why but when I closed the SelectComputer form it doesnt pick up the DialogResult.OK part
0
Fernando SotoRetiredCommented:
If you comment out the line below if the user clicks on the OK button without selecting an item txtHostName will not have anything in it.
Else
    'txtHostName.Text = "No Results"
End If

Open in new window

By using the Close command in the SelectComputer form you are closing and disposing of the form. This is normaly not a problem except when you show the form with the ShowDialog method because in the form you used the ShowDialog method it is still using the variables of the SelectComputer form. Now you have not seen the program crash because you accessed a Form after it has been disposed of and this is because Garbage Collection did not happened yet and so the varables were still accessable but you will find that this will not always be the case because Garbage Collection is non deterministic.

Also accessing the Main form from within the Dialog form is bad practice because it links the Dialog box to the Main form only and therefor can not be used anywhere else.

Please post the Main form complete function/event where the pertinate code is as well as the complete SelectComputer form.
0
fruitloopyAuthor Commented:
Main form:
    Function GetComputers(term As String) As IEnumerable(Of String)

        If txtUsernameSc.Text = "" Then
            Dim result1 = MessageBox.Show("UserName field is empty and must contain an entry", "Missing UserName", MessageBoxButtons.OK, MessageBoxIcon.Error)
            If result1 = Windows.Forms.DialogResult.OK Then
                txtUsernameSc.Focus()
            End If
        Else

            Try

                Application.DoEvents()

                Using searcher As New DirectorySearcher("(&(objectClass=computer))")
                    searcher.PropertiesToLoad.Add("name")
                    searcher.PropertiesToLoad.Add("description")
                    Dim computers = (From computer As SearchResult In searcher.FindAll()
                           Let entry = computer.GetDirectoryEntry()
                           Where Not String.IsNullOrEmpty(entry.Properties("description").Value) _
                           AndAlso entry.Properties("description").Value.ToString().IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1
                           Select New With {.Name = CType(entry.Properties("name").Value, String), .Description = CType(entry.Properties("description").Value, String)})

                    If computers.Count = 0 Then
                        txtHostName.Text = "No Results"
                    ElseIf computers.Count > 1 Then
                        Dim names = computers.Select(Function(x) x.Name + " - Last Logon - " + x.Description).ToList()
                        Dim selectForm As New SelectComputer()
                        selectForm.NameList = names
                        If selectForm.ShowDialog(Me) = DialogResult.OK Then
                            txtHostName.Text = selectForm.selectedName
                        Else
                            'txtHostName.Text = "No Results"
                        End If
                        selectForm.Dispose()
                    Else
                        txtHostName.Text = computers.First().Name
                    End If
                    Return computers.Select(Function(x) x.Name)
                End Using
            Catch ex As Exception

            End Try

        End If

    End Function

Open in new window


SelectComputer Form:
Public Class SelectComputer

    Public NameList As New List(Of String)
    Public selectedName As String = "No Results"

    Private Property DialogResult As Windows.Forms.DialogResult


    Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
        If ListBox1.SelectedItem IsNot Nothing AndAlso Not String.IsNullOrEmpty(ListBox1.SelectedItem.ToString) Then
            selectedName = ListBox1.SelectedItem.ToString()
            Dim name As String = selectedName.Split(" "c)(0)
            Main.txtHostName.Text = name
        End If

        Me.DialogResult = DialogResult.OK
        Me.Close()
    End Sub

    Private Sub BtnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        Me.DialogResult = DialogResult.Cancel
        Me.Close()
    End Sub

    Private Sub SelectComputer_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ListBox1.Items.Insert(0, "Select one:")
        ListBox1.Items.AddRange(NameList.ToArray)
    End Sub
End Class

Open in new window


I did want it so that when the user selects a computer name and clicks select it closes the form

Thanks
0
Fernando SotoRetiredCommented:
Hi fruitloopy;

From Microsoft documentation Form.DialogResult Property
The dialog result of a form is the value that is returned from the form when it is displayed as a modal dialog box. If the form is displayed as a dialog box, setting this property with a value from the DialogResult enumeration sets the value of the dialog box result for the form, hides the modal dialog box, and returns control to the calling form. This property is typically set by the DialogResult property of a Button control on the form. When the user clicks the Button control, the value assigned to the DialogResult property of the Button is assigned to the DialogResult property of the form.

When a form is displayed as a modal dialog box, clicking the Close button (the button with an X in the top-right corner of the form) causes the form to be hidden and the DialogResult property to be set to DialogResult.Cancel. The Close method is not automatically called when the user clicks the Close button of a dialog box or sets the value of the DialogResult property. Instead, the form is hidden and can be shown again without creating a new instance of the dialog box. Because of this behavior, you must call the Dispose method of the form when the form is no longer needed by your application.

You can use this property to determine how a dialog box is closed in order to properly process the actions performed in the dialog box.

To your question, "I did want it so that when the user selects a computer name and clicks select it closes the form", Filling the Property DialogResult with a value from the enumeration will hide the DialogBox and return to the calling program and in the Main Form note that I had placed a selectForm.Dispose() which will close and properly dispose of it after it is no longer needed.

But if it works fine for you as it is fine. Thanks and please don't forget to close the question.
0
fruitloopyAuthor Commented:
Did the job for me , thanks for your help
0
Fernando SotoRetiredCommented:
Not a problem fruitloopy, glad to help.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.