Creating parent and child nodes with a treeview and duplicate strings

This topic contains 11 replies, has 2 voices, and was last updated by Profile photo of john Mccarthy john Mccarthy 1 year, 8 months ago.

  • Author
    Posts
  • #23433
    Profile photo of john Mccarthy
    john Mccarthy
    Participant

    I am creating a GUI based script that when the user enters a username, is retrieves a comma delimited log file with information like date and time logged in, the machine they logged into, etc.
    As part of the GUI I would like to use a TreeView to present them with a list of the MAC addresses that the username they entered has logged into.
    In some cases there are many duplicates, for different times logged in over the course of a year.
    I would like to be able to display the unique instances as parent nodes, and then for each duplicate instance, add it as a child node to the corresponding parent node along with the time they logged in.
    The properties im selecting from the log file are hostname and date.
    I have what i think is part of the solution, the adding of the unique nodes, and its working as i expected, but am having quite a tough time adding the duplicate nodes as child nodes to the corresponding parent nodes.

    Ex: if the user has logged into hostname COMP1, 6 times throughout the log file, I want to display COMP1 as a parent node and if the users presses the + symbol, they will see the 6 instances listed below with the date property attached.

    Here is some of my current code:

    		$array = Import-Csv $filepath\$username.txt | Where-Object {$_.EventType -eq "TS Session Connected" -or $_.EventType -eq "Logon"} | select -ExpandProperty hostname | sort -Unique
    
    		$array2 = Import-Csv $filepath\$username.txt | Where-Object {$_.EventType -eq "TS Session Connected" -or $_.EventType -eq "Logon"} | select -ExpandProperty Date | sort -Unique
    
    		#Loops through and singles out each host name, and adds it as a treenode 
    		for ($i = 0; $i -lt $array.Count; $i++) {
        			$node = $treeviewHostnames.Nodes.Add($array[$i]) | Out-Null
        		}
    
  • #23440
    Profile photo of Daniël
    Daniël
    Participant

    You cannot add custom objects to a treenode, only other treenodes, see https://msdn.microsoft.com/en-us/library/system.windows.forms.treenode%28v=vs.110%29.aspx

    For example:

    $TreeNode = New-Object -TypeName System.Windows.Forms.TreeNode -ArgumentList 'Test'
    $ChildNode = New-Object -TypeName System.Windows.Forms.TreeNode -ArgumentList 'Test2'
    
    $TreeNode.Nodes.Add($ChildNode)
    
  • #23446
    Profile photo of john Mccarthy
    john Mccarthy
    Participant

    I apologize if I wasnt clear in my intial description, I AM trying to add other treenodes.
    I want to create a parent node of each unique mac address that is logged into and then for each other instance of a duplicate MAC, create a child node and nest it under the corresponding parent node.

    So that the output looks similar to this, but in a treeview:

    + COMP1
    – COMP1 – 3/15/15 – 10:21 pm
    – COMP1 – 3/16/15 – 9:07 am

    + COMP2
    – COMP2 – 4/12/14 – 6:06 am
    – COMP2 3/12/14 – 7:07 am
    – COMP2 3/10/14 – 6:15 am

  • #23447
    Profile photo of john Mccarthy
    john Mccarthy
    Participant

    That did not format the way I meant it to, I apologize, the " – COMP" lines are supposed to be indented

  • #23468
    Profile photo of Daniël
    Daniël
    Participant

    Ok, I understand, but in your code you're trying to add an item from array $array, which is created from Import-CSV – so it does not contain any treenode objects.

    What errors do you get when you try to add a child node?

  • #23469
    Profile photo of john Mccarthy
    john Mccarthy
    Participant

    I am not getting any errors, though i have not been able to figure out how to add the child nodes to the corresponding parent nodes.

    The only way it has worked for me thus far is to convert the objects from the CSV file to a string (in this case by using select -expandproperty). I thought I was creating the treenode objects by using the line

    			$node = $treeviewHostnames.Nodes.Add($array[$i]) | Out-Null
    

    Perhaps I am approaching it incorrectly, but currently when I use my listed code above I get output like the image attached.

    My main question/challenge here then is: How do I create this list of Parent nodes and then add the child nodes?

    I apologize if what i say is not very clear, I'm not great at getting this into words, but I appreciate your patience!

  • #23686
    Profile photo of john Mccarthy
    john Mccarthy
    Participant

    Still hoping someone can help me with this! Thank you!

  • #23739
    Profile photo of Daniël
    Daniël
    Participant

    Hi John, sorry for this late reply, but I've an example for you:

    First of all, I started with a CSV file with some example information:

    HostName,LastLogon
    COMP1,032820151913
    COMP1,032720151913
    COMP2,032820151913
    COMP2,032720151913
    

    Next, I've build a script

    function Add-Node { 
            param 
            ( 
                $RootNode, 
                $HostName,
                $LastLogon
            )
    
            $newNode = new-object System.Windows.Forms.TreeNode  
            $newNode.Name = "$HostName - $LastLogon"
            $newNode.Text = "$HostName - $LastLogon" 
            
            If($RootNode.Nodes.Tag -contains $HostName)
            {
                $HostNode = $RootNode.Nodes | ?{$_.Tag -eq $HostName}
            }
            Else
            {
                $newHostNode = new-object System.Windows.Forms.TreeNode
                $newHostNode.Name = $HostName
                $newHostNode.Text = $HostName
                $newHostNode.Tag = $HostName
    
                $Null = $RootNode.Nodes.Add($newHostNode)
                $HostNode = $RootNode.Nodes | ?{$_.Tag -eq $HostName}
            }
    
            $Null = $HostNode.Nodes.Add($newNode)
    } 
    
    $Form = New-Object system.Windows.Forms.Form
    $Form.Text = "TreeView"
    
    $TreeView = New-Object System.Windows.Forms.TreeView
    $System_Drawing_Size = New-Object System.Drawing.Size
    $System_Drawing_Size.Width = 224
    $System_Drawing_Size.Height = 200
    $TreeView.Size = $System_Drawing_Size
    
    $System_Drawing_Point = New-Object System.Drawing.Point
    $System_Drawing_Point.X = 13
    $System_Drawing_Point.Y = 37
    $TreeView.Location = $System_Drawing_Point
    
    $Form.Controls.Add($TreeView)
    
    $TreeNode = New-Object -TypeName System.Windows.Forms.TreeNode -ArgumentList 'Computers'
    $TreeNode.Tag = 'Computers'
    
    $CSV = Import-CSV .\LogonInfo.txt
    
    Foreach($Computer in $CSV)
    {
        Add-Node -RootNode $TreeNode -HostName $Computer.HostName -LastLogon $Computer.LastLogon
    }
    
    $Null = $TreeView.Nodes.Add($TreeNode)
    
    $TreeView.ExpandAll()
    $Form.ShowDialog()
    

    What this script does is basically
    1. Setup a simple form to display the TreeNode in a TreeView
    2. Add a root TreeNode tagged Computers, we will add all computers to this TreeNode
    3. Import the CSV file
    4. Loop through the CSV and add a node foreach computer in the CSV. The Add-Node function checks if a childnode with a tag which equals the hostname of the computer is present, if it is, we simply add the logon information to that node. If it isn't, we create a new childnode using the hostname of the computer. Next, we select that newly created node to add the logon information.
    5. Last, the script expands all nodes and displays the form. I've attached an example screenshot how this looks like.

    Hope this is helpful.

  • #23746
    Profile photo of john Mccarthy
    john Mccarthy
    Participant

    Wow Dan you have outdone yourself! After seeing what you implemented it seems so easy now! I think i was approaching it in a more complex way and getting in over my head. Thank you for your help!

  • #23849
    Profile photo of john Mccarthy
    john Mccarthy
    Participant

    After some testing and tweaking, it is working perfectly on powershell v3, but on v2 i always get this error:

    You cannot call a method on a null-valued expression.
    At line:28 char:36
    +         $Null = $HostNode.Nodes.Add < <<< ($newNode)
        + CategoryInfo          : InvalidOperation: (Add:String) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull
    

    Have tried to debug this and I am getting nowhere, I"m not sure if its saying that $hostnode is null valued or if $newnode is null valued.
    Any suggestions?

  • #23917
    Profile photo of Daniël
    Daniël
    Participant

    Well, this line will not work in V2 because it lacks auto member enumeration:

    If($RootNode.Nodes.Tag -contains $HostName)
    

    In V2 you should write:

    If(($RootNode.Nodes | Foreach-Object {$_.Tag}) -contains $HostName)
    
  • #23933
    Profile photo of john Mccarthy
    john Mccarthy
    Participant

    That did the trick! Thank you for your help. I am still very young in my powershell skills and have mostly learned on V3. Still learning that the minor syntactical differences make a huge imapct!

You must be logged in to reply to this topic.