Custom Object - Cannot place Values in Hash Table

by n3rdbiker at 2012-08-13 19:00:43

I know this doesn’t sound like a noob question, but believe me I am. I have grand ideas and many books… Most of them Manning Press, most of them written by Don Jones.

I am trying to create a custom object using the c# notation <– I have done this. I have added my properties, and assigned some values. My trouble is that when I assign the values to a hash table using a notation like: $hash.add($object.name,$object) what is entered into the table is a reference to the object, not the value – I can overcome this on the name by using: $object.name.clone() but the $object itself doesn’t have a clone() method. For the life of me I can’t find how to add one to it, and wouldn’t know where to begin. – so, as I loop through the script, all of my values appear the same when I print my $hash table.

Many thanks–and I dig your books (if you read this Don) I’m dissapointed that I can’t purchase the Meap of your Learn PowerShell Toolmaking in a Month of Lunches yet.

Respectfully,

J
by DonJ at 2012-08-13 19:56:36
So, if you’re hell-bent on using the C# syntax, I’d suggest asking Kirk on the "Advanced Scripting" forum, or posting on StackOverflow. I don’t really do C# :).

I’d do this:

$obj | Add-Member -Name $whatever.name -Value $whatever -MemberType NoteProperty

Or…

$props = @{$that.name=$that;$this.name=$this}
New-Object -Type PSObject -Prop $props


Which in my experiences passes ByValue rather than ByReference. That said, sometimes stuff like this is just a logic error rather than a coding error. I’m assuming, since you didn’t post any code, that your loop’s logic is sound. But, if you want to post a concise sample snippet of what you’re doing, we can check that.

Thanks for the kind words :). There’s a bundle of the new books for pre-order at http://store.concentratedtech.com/lunchesbundle.php; the MEAP should go live shortly. I think they’re in the process of counting pages and finalizing the price, or something. I know we’re off to tech proofing shortly, which happens in parallel with the MEAP.
by n3rdbiker at 2012-08-14 05:51:48
Mr. Jones I haven’t even worked out the loop yet but it seems fairly straight forward… I have been testing code chunks by hand…
PS C:\Users\jason.gibson> $systems = @{}
$props = @{name=$null;test=$null}
$system = New-Object -TypeName psobject -Property $props

PS C:\Users\jason.gibson> $system.name = "Computer 1"
PS C:\Users\jason.gibson> $system.test = "Test 1"
PS C:\Users\jason.gibson> $systems.Add($system.name.Clone(),$system)
PS C:\Users\jason.gibson> $systems

Name Value
---- -----
Computer 1 @{test=Test 1; name=Computer 1}

PS C:\Users\jason.gibson> # imagine we just looped and are going to assing values <br>PS C&#58;\Users\jason&#46;gibson&gt; # from another machine&#46;&#46;&#46;<br>PS C&#58;\Users\jason&#46;gibson&gt; $system&#46;name = &quot;Computer 2&quot;; $system&#46;test = &quot;Test 2&quot;<br><br>PS C&#58;\Users\jason&#46;gibson&gt; # now look at the $systems Hash Table<br>PS C&#58;\Users\jason&#46;gibson&gt; $systems<br><br>Name Value <br>---- ----- <br>Computer 1 @{test=Test 2; name=Computer 2} <br><br>PS C&#58;\Users\jason&#46;gibson&gt; # notice my values for Computer 1 changed&#46;&#46;&#46;</code><br>This is the same probelm I ran into while using my C# implementation... when I pass the whole object to the hash table, it appears to be only passing a variable reference and not the value of the variable. Using the clone() method on the string keeps the &quot;Name&quot; key in the hash table from changing.<br><br>I know you can crack this one... Obi-Don-Kenobi</blockquote>by DonJ at 2012-08-14 06:43:05<blockquote>Yeah, I think this might just be a logic error. Let me walk through it.<br><br><code><br>PS C&#58;\Users\jason&#46;gibson&gt; $systems = @{}<br>$props = @{name=$null;test=$null}<br>$system = New-Object -TypeName psobject -Property $props<br></code><br><br>Ok, with you so far. <br><br><code><br>PS C&#58;\Users\jason&#46;gibson&gt; $system&#46;name = &quot;Computer 1&quot;<br>PS C&#58;\Users\jason&#46;gibson&gt; $system&#46;test = &quot;Test 1&quot;<br>PS C&#58;\Users\jason&#46;gibson&gt; $systems&#46;Add($system&#46;name&#46;Clone(),$system)<br>PS C&#58;\Users\jason&#46;gibson&gt; $systems<br><br>Name Value <br>---- ----- <br>Computer 1 @{test=Test 1; name=Computer 1} <br></code><br><br>Don't understand why you did it that way. If you want the name to be &quot;Computer 1&quot; and you want the Test property to be &quot;Test 1,&quot; why didn't you just create the object that way in the first place? And I don't understand why you're using the Add() method. It's a poor way to accomplish what you're after. Once you create an object using $systems as the property bag, you shouldn't be messing around with $systems anymore. If you want to add a property to the object in $system, use Add-Member. Or just put the property there in the first place.<br><br><code><br>PS C&#58;\Users\jason&#46;gibson&gt; # imagine we just looped and are going to assing values
PS C:\Users\jason.gibson> # from another machine...
PS C:\Users\jason.gibson> $system.name = "Computer 2"; $system.test = "Test 2"

PS C:\Users\jason.gibson> # now look at the $systems Hash Table
PS C:\Users\jason.gibson> $systems

Name Value
---- -----
Computer 1 @{test=Test 2; name=Computer 2}

PS C:\Users\jason.gibson> # notice my values for Computer 1 changed...


Well, sure. First, you’re re-using the object in $system. You shouldn’t. If you’ve got a new object, you create a new object, you don’t overwrite the old one.

Your code should look something like this:


foreach ($computer in $collection) {
# assume $computer.name has the computer name. We populate $data.test and $data.thing with data from that computer.
$props = @{‘name’=$computer.name;‘test’=$data.test;‘thing’=$data.thing}
$obj = New-Object -Type PSObject -prop $props
Write-Output $obj
}


You’re running New-Object for each new computer - you’re not re-writing into the object you created for an earlier computer. You want a fresh new object for each thing you intend to output. Otherwise, yeah, you’re just repeatedly changing the same thing.
by n3rdbiker at 2012-08-14 07:41:56
Don, I’ll give it a go.
The reason I was re-using the object was that I was just trying to use it as a place holder for the data as I calculated it… then would send it on to the hash table for output, to the shell prompt or to a CSV file.

It actually dawned on me that I could possilby break my reference links by doing something like this: $hash = $hash.clone() my goas was to end up at the prompt being able to type a reference like: $systems.computername.ipaddress and it would return the value…

I wasn’t sure of the impact of creating 5000 objects, one for each machine in the environment, therefore I was trying to avoid the object route.

Thanks for all of your help and instruction - I enjoy your teaching style and am debating picking up a subscription to your videos as well…
by DonJ at 2012-08-14 08:08:40
There’s no harm in creating a ton of objects - just emit each one to the pipeline once it’s populated. PowerShell’s designed to deal with that just fine.

It isn’t necessarily designed for "templating," thought. And it’s no faster to just re-create the stuff - you’re not saving yourself any time or other resources, in other words - and you’re making the programming harder to write (and maintain). Go with "straightforward."
by poshoholic at 2012-08-15 12:34:21
Just to add one thought to this: encapsulating the logic that defines the custom objects you are creating is a really good approach to take. That’s about as close as you’ll get to having a template to work with. You end up with separate instances of each object, but that’s the right approach to take. As Don indicated, trying to re-purpose one object over and over again is the wrong way to go.

You can see a few examples of how this can be done over on the Advanced PowerShell forum on this thread: viewtopic.php?f=5&t=15
by juneb_msft at 2012-08-17 08:28:38
Is there a reason that the solutions don’t use PSCustomObject? Are you just sticking with v2 solutions because that’s what people are using in production?

Thanks,
June

June Blender [MSFT]
Windows PowerShell documentation