New-Object PSObject –Property [HashTable]

New-Object PSObject –Property [HashTable]

Rate This
  • Comments 24
Let me start of by suggesting you take a few minutes and read Laerte Junior’s excellent blog 
entry Exceptional PowerShell DBA Pt1 Orphaned Users. Laerte does a great job describing the
scenario, the approach he took to solving it and then he included the scripts! Really good
stuff Laerte!
When I looked at Laerte’s code, I recognized one of my least favorite PowerShell V1isms:
		$Object = New-Object PSObject                                       
               $Object | add-member Noteproperty LineNumber       $LineNumber                 
               $Object | add-member Noteproperty Date             $TodayDate              
               $Object | add-member Noteproperty ServerName       $svr            
               $Object | add-member Noteproperty DatabaseName     $Database            
               $Object | add-member Noteproperty UserName         $user.name            
               $Object | add-member Noteproperty CreateDate       $CreateDate            
               $Object | add-member Noteproperty DateLastModified $DateLastModified            
               $Object | add-member Noteproperty AsymMetricKey    $user.AsymMetricKey            
               $Object | add-member Noteproperty DefaultSchema    $user.DefaultSchema            
               $Object | add-member Noteproperty HasDBAccess      $user.HasDBAccess            
               $Object | add-member Noteproperty ID               $user.ID            
               $Object | add-member Noteproperty LoginType        $user.LoginType            
               $Object | add-member Noteproperty Login            $user.Login            
               $Object | add-member Noteproperty Orphan           ($user.Login -eq "")            
                                

Gosh that is a horrible looking thing.  This is one of the things we fixed with PowerShell V2 so you take a few minutes to
learn this so you never have to do that mess again.  Let’s get some help:

PS> Get-Help New-Object -Parameter Property

-Property <hashtable>
    Sets property values and invokes methods of the new object.
    Enter a hash table in which the keys are the names of properties or methods and the values are property value
    s or method arguments. New-Object creates the object and sets each property value and invokes each method in
    the order that they appear in the hash table.
    If the new object is derived from the PSObject class, and you specify a property that does not exist on the o
    bject, New-Object adds the specified property to the object as a NoteProperty. If the object is not a PSObjec
    t, the command generates a non-terminating error.
    Required?                    false
    Position?                    named
    Default value               
    Accept pipeline input?       false
    Accept wildcard characters?  false

 

Thats right – you can now specify a hashtable and we’ll set these as NoteProperties on an object.  What that means is that you can now write code like this:

    $Object = New-Object PSObject -Property @{            
        LineNumber       = $LineNumber                 
        Date             = $TodayDate              
        ServerName       = $svr            
        DatabaseName     = $Database            
        UserName         = $user.name            
        CreateDate       = $CreateDate            
        DateLastModified = $DateLastModified            
        AsymMetricKey    = $user.AsymMetricKey            
        DefaultSchema    = $user.DefaultSchema            
        HasDBAccess      = $user.HasDBAccess            
        ID               = $user.ID            
        LoginType        = $user.LoginType            
        Login            = $user.Login            
        Orphan           = ($user.Login -eq "")            
    }                           
                                    

or if you prefer:

   $hash = @{            
        LineNumber       = $LineNumber                 
        Date             = $TodayDate              
        ServerName       = $svr            
        DatabaseName     = $Database            
        UserName         = $user.name            
        CreateDate       = $CreateDate            
        DateLastModified = $DateLastModified            
        AsymMetricKey    = $user.AsymMetricKey            
        DefaultSchema    = $user.DefaultSchema            
        HasDBAccess      = $user.HasDBAccess            
        ID               = $user.ID            
        LoginType        = $user.LoginType            
        Login            = $user.Login            
        Orphan           = ($user.Login -eq "")            
    }                           
                                    
    $Object = New-Object PSObject -Property $hash            

 

This is SO much better than V1 – be sure to use it and to tell all your friends about it as well! 

Experiment!  Enjoy!  Engage!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Leave a Comment
  • Please add 8 and 5 and type the answer here:
  • Post
  • Nice post Jeffrey! The simplifed syntax is great. But can you tell me why if I use the PowerShell V2 way my NoteProperties aren't sorted in the order I create them like they do using the V1 way?

    Example:

    $objectV1 = New-Object PSObject

    $objectV1 | Add-Member NoteProperty FirstName MyFirstName

    $objectV1 | Add-Member NoteProperty LastName MyLastName

    $objectV1 | Add-Member NoteProperty Address MyAddress

    $objectV1 | Add-Member NoteProperty City MyCity

    $objectV1 | Add-Member NoteProperty State MyState

    $objectV1 | Add-Member NoteProperty Zip MyZip

    $objectV1

    $objectV2 = New-Object PSObject -Property @{

       FirstName = 'MyFirstName'

       LastName = 'MyLastName'

       Address = 'MyAddress'

       City = 'MyCity'

       State = 'MyState'

       Zip = 'MyZip'

    }

    $objectV2

    FirstName : MyFirstName

    LastName  : MyLastName

    Address   : MyAddress

    City      : MyCity

    State     : MyState

    Zip       : MyZip

    City      : MyCity

    LastName  : MyLastName

    Address   : MyAddress

    State     : MyState

    FirstName : MyFirstName

    Zip       : MyZip

  • That is the effect of using a hashtable.  By definition, you cannot assume any ordering of the keys of a hashtable.  For some reason they ended up in that order:

    PS>$x= @{

      FirstName = 'MyFirstName'

      LastName = 'MyLastName'

      Address = 'MyAddress'

      City = 'MyCity'

      State = 'MyState'

      Zip = 'MyZip'

    }

    ______________________________________________________________________________________________________________

    PS>$x.Keys

    City

    LastName

    Address

    State

    FirstName

    Zip

    jps

  • Thank you very much. I'm actually a DBA who likes to powershell and not a powershell expert who likes to be DBA. It was the way I found to solve my problem to add the objects from  various serevrs and one thing I always ask to powersehll community is to help me improve the code, optimize, and so I can understand more how I can make the necessary advantage of this fantastic shell.

    Thanks for the tip!! I'm already changing my scripts!!

  • Thank you very much. I'm actually a DBA who likes to powershell and not a powershell expert who likes to be DBA. It was the way I found to solve my problem to add the objects for various servers and one thing I always ask to community is to help me improve the code, optimize, and so I can understand more how I can make the necessary advantage of this fantastic shell.

    Thanks for the tip!! I'm already changing my scripts

  • Looks very nice, but doesn't help very much if you have to process text with name:value pairs from the messagage field of the security eventlog. I got about the same performance when I add the values one by one as noteproperty or when I collect them in a hash and add this in one step.

    I posted the code using adding the hash as property at http://pauerschell.blogspot.com/2009/12/using-powershell-to-filter-eventlog.html

  • Hi Jeffrey,

    I wonder why you didn't add release note which include changes since posh v1.0 on posh v2 RTM package.

  • When V2 RTM was released, one of the first things I did was replacing accelerators "$var = 1 | Select-Object Prop1, Prop2, ..." (well known and very effective trick) with modern native V2 approach "$var = New-Object -Property @{...}". And then, yes, I very quickly realized that in fact I often wanted properties to be in particular order, for various reasons. Thus, I had to restore old good tricks in approximately 50% of cases. This new feature is excellent, no doubts, but because of unpredictable property order it still does not cover what I expect from New-Object.

  • Would it be possible (for an end user or for Microsoft in a future version) to somehow apply an adapter - similar to the way array's are adapted for more flexible array use - that would honor the initial order of the hashtable's keys? Obviously it would be a breaking change to use a different implementation of IDictionary, but the unordered nature of keys in a hashtable has always made them slightly less useful in PowerShell IMHO.

  • I've started using PS just two weeks ago, and I am impressed. As far as scripting is involved, I was sooo much more productive, it's a delight.

    But! Using PS *interactively*, as opposed to writing a batch file and executing it, is one very ugly experience. As commenting on the blog post probably is not the best communication channel, where is the proper place for me to whine and complain how bad is the PS command line interpreter?

  • Why is it that New-Object does not accept the most obvious (at least to me) for the TypeName Parameter namely a real Type?

    e.g.

    New-Object [System.Text.StringBuilder]

    It's not a big deal. I'm just wondering...

  • @Stranger:  I did some testing and found a work around.

    New-Object ([System.Text.StringBuilder])

    It appears to be a problem with the PowerShell parser.

  • @Jason - in strangers example he was passing a string "[System.Text.StringBuilder]" but in your example the parenthases causes PowerShell to evaluate an expression which produces a Type object. Type.ToString is then used to send the string parameter New-Object expects which becomes "System.Text.StringBuilder" so the two are not equivalent.

    It may seem like Stranger is sending a Type object

    to New-Object but in fact the parameter parser considers that a string. Anything in parenthases is evaluated as an expression. It's by design.

  • Very nice! When creating tens of thousands of custom objects, though, is this method (using a hash) the best for performance?  If speed is more important than code elegance, what's the best way to create large numbers of custom objects with many (10+) new properties?  Thanks!

  • Hey Rinimbi, regarding the performance of PSObjects, Karl Prosser, mow, and Brandon Shell have been batting this around for a while. Check out the following URL and in the first sentence he links to other posts that benchmark various methods of creating custom objects.

    http://karlprosser.com/coder/2008/06/12/generating-a-propertybag-aka-pscustomobject-in-c/

    But depending on your circumstances, I've found the best way to create a huge number of objects with uniform structure is to use the Add-Type cmdlet in PowerShell 2.0 to create an on-the-fly .NET class in C# syntax.

  • I've started using PS just two weeks ago, and I am impressed. I am so much more productive in terms of scripting, super. Really a big thank you for explaining the Real Time problem with the PowerShell parser.

Page 1 of 2 (24 items) 12