generating a "PropertyBag" aka PScustomObject in C#
June 12th, 2008 by KarlBased on the performance testing and work being done by myself , mow , Brandon Shell and others the question has come up what is the quickest way to generate a PSCustomObject, whether in script , on in C#, and how do you even do it in C#?
Some typical ways of doing in PowerShell have been either something like the following trick:
$a = 1 | select a , b , c , d
or with using the Add-member cmdlet as below:
$a | add-member -membertype noteproperty -name status -value done
however both are really slow. There is another way to do it in script, and that is directly with the PSobject, but still PowerShell (especially version 1) has a huge overhead when creating new objects with new-object but below is an example none the less.
$obj = new-Object system.Management.Automation.PSObject
$note = new-object System.Management.Automation.PSnoteproperty "karl" , "a value"
$obj.psobject.members.add( $note );
But if you really want to do speed, or if you have need to generate these objects in a cmdlet regardless of speed here is how you can do it in C#.
public static PSObject newPsCustomObject2()
{
//Creating a PSobject without any parameters in the constructor creates a PSCustomObjectg
PSObject obj = new PSObject();
//PSNoteProperties are not strongly typed but do contain an explicit type.
obj.Properties.Add(new PSNoteProperty("age",24));
obj.Properties.Add(new PSNoteProperty("name","jon"));
//Alias allow you to cast one property as another as well as just plain aliasing
obj.Properties.Add(new PSAliasProperty("ageasstring","age",typeof(string)));
return obj;
}
Some notes about the above, I didn’t show how you could add ScriptProperties or ScriptMethods yet as I wanted to keep it simple and not cover creating scriptblocks. Before I go lets performance test this baby compared to creating this in pure PowerShell.
So in the:
1) first corner we have creating the object with select-object, then setting the properties.(but we can’t set the alias)
2) Creating the object with new-object, then using add-member to add all the properties.
3) calling our static method above.
#select-object version
for($i = 0;$i -lt 50000;$i++) { $a = 1 |Select-Object age, name; $a.age = 24; $a.name = "john" }
#add-member version
for($i = 0;$i -lt 50000;$i++)
{ $a = new-Object psobject;
$a | add-member -membertype noteproperty -name age -value 24
$a | add-member -membertype noteproperty -name name -value "john"
$a | add-member -membertype aliasproperty -name "ageasstring" -value "age" -secondvalue "string"
}
#Our fast version
for($i = 0;$i -lt 50000;$i++) { $a = [snapinini.newobjecthelper]::newPsCustomObject2(); }
so we are creating 50,000 objects and the results are.
| select-object | 27.15 seconds. |
| add-member | 118.79 seconds |
| C# method | 1.9 seconds. |
and i used to complain with the performance hit of a address lookup for a method in a C++ virtual method table!!
at worst the official add-member technique is over 60 times slower than calling C#, and thats not really RAW C#, thats still powershell invoking a C# method 50,000 times, and powershell managing a loop.
if fact just to test i added another test
$a = [snapinini.newobjecthelper]::newPsCustomObject3();
where newPSCustomObject3() moves the 50,000 loop to inside C#.. and here the speed is 0.95 seconds, so about half the speed of invoking the C# method from powershell each time – this speed difference I am happy with though. The PowerShell team seem to have done a good job of invoking C# methods quickly.
Another day I should investigate the speed of creating objects that have been created with the extended type system.
I’d love if somebody can run these tests in v2.
Also sometime soon I shall share a helper function you can use to quickly generate a PScustomObject with properties and values you specify in script.
-Karl
Posted in Bare Metal, Gotchas Etc, Powershell, performance, pscom, rant | 3 Comments »
