Creating parent and child nodes with a treeview and duplicate strings

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

You cannot add custom objects to a treenode, only other treenodes, see

For example:

$TreeNode = New-Object -TypeName System.Windows.Forms.TreeNode -ArgumentList 'Test'
$ChildNode = New-Object -TypeName System.Windows.Forms.TreeNode -ArgumentList 'Test2'


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

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

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?

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!

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

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:


Next, I’ve build a script

function Add-Node { 

        $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}
            $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


$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)


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.

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!

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?

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)

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!