Blogroll

Search

generating a "PropertyBag" aka PScustomObject in C#

June 12th, 2008 by Karl

Based 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, performance, Powershell, pscom, rant | 6 Comments »

6 Responses

  1. The PowerShell Guy : PowerShell Performance Series Part 2 (.NET method call not always faster as PowerShell shortcut) Says:

    [...] generating a "PropertyBag" aka PScustomObject in C# [...]

  2. TeX HeX Says:

    Thanks a lot Karl! This performance test and the code sample is exactly what I was searching for.

  3. Custom Powershell Objects and Performance | Learn Powershell | Achieve More Says:

    [...] Brandon Shell and Karl Prosser tested this before with some interesting results.  These guys are a lot smarter than me and showed some nice things including using C# code to [...]

  4. Mark Says:

    I was playing with your sample and found a massive performance difference between

    for($i = 0;$i -lt 50000;$i++) { $a = [snapinini.newobjecthelper]::newPsCustomObject2(); }

    and

    $a = @()
    for($i = 0;$i -lt 50000;$i++) { $a += [snapinini.newobjecthelper]::newPsCustomObject2(); }

    Any tips for improving the performance when you write each new object into an array?

  5. Mark Says:

    Worked it out …

    $a = new-object object[] 50000
    for($i = 0;$i -lt 50000;$i++) { $a[$i] = [snapinini.newobjecthelper]::newPsCustomObject2(); }

  6. V Says:

    Thanks very much guys (Mark and Karl). Moving the object creation to C# and using a generic PSObject linkedlist or arraylist, made a huge difference.

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.