There is a post on the PowerShell Team blog about using New-Object – http://blogs.msdn.com/powershell/archive/2009/12/05/new-object-psobject-property-hashtable.aspx
The –property parameter discussed in this post is something that I had only come across recently. In a number of recent posts I have used Add-Type to create a new object by using C# code to define a new class rather than using New-Object and Add-Member. The post on the team blog, plus questions I’d been asked about why I used add-type got me thinking about creating objects.
In PowerShell v1 we used to do this
001
002 003 |
$new1 = New-Object -TypeName PSObject
$new1 | Add-Member -Name p1 -Value 1 -MemberType NoteProperty -PassThru | Add-Member -Name p2 -Value "a" -MemberType NoteProperty |
We would create an object and then use Add-Member to add the properties. The object could then be used
001
002 003 004 |
$new1 | ft -AutoSize
$new1.p1 = "b" |
This would give the results we expect
p1 p2
— —
1 a
p1 p2
— —
b a
Notice that we have been able to change the type of p1 from an integer to a string.
In v2 we get the –property parameter on New-Object
001
002 003 004 005 |
$p = @{
p1 = 1 p2 = "a" } $new2 = New-Object -TypeName PSObject -Property $p |
In this method we create a hash table holding the properties and the values. It can be used when we create the object so that the properties are immediately populated. This is a neater method than the multiple calls to Add-Member we saw earlier.
The object can be used as before
001
002 003 004 |
$new2 | ft -AutoSize
$new2.p1 = "b" $new2 | ft -AutoSize |
with the following results
p2 p1
— —
a 1
p2 p1
— —
a b
Again notice that we can change the type of p1.
If we want to use a PSObject and create properties then using a hash table in v2 involves less typing, looks neater and is probably easier to understand.
In a number of recent posts I have been creating a C# class rather than using PSObject. This is a better variant of that technique showed to me by Doug Finke (thanks Doug)
001
002 003 004 005 006 007 008 009 010 011 012 013 |
$code = @"
public class testobject { public int p1 {get; set;} public string p2 {get; set;} } "@ Add-Type -TypeDefinition $code -Language CSharpversion3 $p = @{ p1 = 1 p2 = "a" } $new3 = New-Object -TypeName testobject -Property $p |
I have created a simple .NET class with our two properties. Add-Type is used to add the definition into PowerShell. I can then create an object using a hash table for the properties. This probably looks more complicated but there is a significant difference when we come to use it
001
002 003 004 |
$new3 | ft -AutoSize
$new3.p1 = "b" $new3 | ft -AutoSize |
gives us
p1 p2
— —
1 a
Exception setting "p1": "Cannot convert value "b" to type "System.Int32". Error: "Input string was not in a correct format.""
At line:16 char:7
+ $new3. <<<< p1 = "b"
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
p1 p2
— —
1 a
We can’t change the type of p1 because it is defined by the class we created. This gives me an extra level of protection on what I’m doing as I can’t make a mistake and set the property to the wrong type.
PowerShell often gives us a number of ways of achieving the goal. In this case choose the one that best fits your requirements.
By: Dmitry on December 10, 2009 at 5:41 am
Hello Richard!
I’ve been reading your blog for a while and I find it very useful. Especially the information about Powershell 2 that you are sharing.
I’ve been anxiously waiting for Powershell 2 release and now that it is out I feel that it suffers from a lack of well-documented best practices. In fact, many of the new features brought by Powershell 2 seem like esoteric knowledge available to a chosen few.
One of the questions that interests me most is a way to make a background job communicate with the current session. The ability to run tasks in the background introduced in Powershell 2 is really really great, since typical scripting languages do not support threads. However, it would be even greater if there was a way for the current Powershell session to somehow communicate with the threads it creates.
I tried to find an answer to this question. A few hours of searching the web turned up nothing. Then I found a forum thread on the stackoverflow.com site. A Microsoft MVP said that it was in fact possible to raise custom events from within a background job and act on them in the current session and promised to write a few words about it. You can find the thread here:
http://stackoverflow.com/questions/1392699/powershell-job-progress-monitoring
However, the man seemed to break his promise and forgot about it.
Richard, may be you can shed some light on this? Please, please, please!