How objects are sent to and from remote sessions

How objects are sent to and from remote sessions

  • Comments 5

Instead of piping unstructured text, Windows PowerShell pipes objects between commands in a pipeline.  As a consequence PowerShell remoting also deals with objects when passing data to and from remote sessions.  This post explains how remote objects are serialized and which types of objects can be sent with full fidelity.  You might want to refer to this post when passing arguments to remote commands or when designing remoting-friendly cmdlets or functions.

Property bags

You might have noticed “Deserialized” prefix in front of type names of some objects received from a remote session:

PS C:\> $s = New-PSSession localhost
PS C:\> Invoke-Command $s { Get-Process } | Get-Member


   TypeName: Deserialized.System.Diagnostics.Process
...

Objects that have the "Deserialized." prefix in their type names are property bags that contain a deserialized representation of public properties of the corresponding remote, live objects. As you can see in the output of Get-Member those property bags don't expose any methods except ToString(), because usually methods cannot be invoked in the remote session (for example, System.Diagnostics.Process.Kill() can't act on a remote process). Similarly setting and getting property values of the property bags doesn't execute any code (for example WorkingSet property of Deserialized.System.Diagnostics.Process.WorkingSet is only a snapshot and doesn't get updated when the remote process uses more memory).

Serialization settings (i.e. serialization depth) are controlled to some extent by the extended type system and types.ps1xml files.  See an older post for more details.

Primitive types

Some objects can be deserialized into a "live" object. An example are some primitive types, like integers:

PS C:\> $s = New-PSSession
PS C:\> Invoke-Command $s { 123 } | Get-Member


   TypeName: System.Int32
...

Below is a list of all primitive (serialization-wise) types:

Almost-primitive types

Some types are not deserialized with full fidelity, but nevertheless behave as primitive types for most practical purposes.

For example Enums are deserialized into an underlying integer (with a preserved ToString value).  The deserialized value is almost indistinguishable from the original enum, because PowerShell can implicitly cast from the integer to the original enum type.  One can also request an explicit cast: scripters can just use the scripting language and .NET developers can call into one of LanguagePrimitives methods to perform a cast (using those methods will make the cast go through the scripting engine and take account of PSObject wrapping and other casting quirks).

Similarly, deserializer will preserve contents of lists, but might change the actual type of the container. The change of the underlying container type is usually invisible, because there is a built-in cast from any container to an appropriate array. Below is a list of recognized and handled container types:

The bottom line of this section is that non-primitive types can be remoting-friendly as long as they support casting from a primitive value.

Rehydration

PowerShell exposes a mechanism by which third parties can instruct the deserializer to "rehydrate" additional types into "live" objects.  Rehydration is done by casting the deserialized property bag to the type specified in "TargetTypeForDeserialization" property in the Types.ps1xml file.  Below is an example taken out of $pshome\types.ps1xml, that shows how rehydration is set up for System.Net.IPAddress type:

   
    <Type>
         <Name>Deserialized.System.Net.IPAddress</Name>
         <Members>
             <MemberSet>
                <Name>PSStandardMembers</Name>
                <Members>
                    <NoteProperty>
                        <Name>TargetTypeForDeserialization</Name>
                        <Value>Microsoft.PowerShell.DeserializingTypeConverter</Value>
                    </NoteProperty>
                </Members>
              </MemberSet>
          </Members>
    </Type>

The Microsoft.PowerShell.DeserializingTypeConverter is a special class that inherits from System.Management.Automation.PSTypeConverter and provides details of type conversion from Deserialized.System.Net.IPAddress to a live IPAddress object.  The rehydration of IPAddress simply passes a deserialized ToString value to the static IPAddress.Parse method, but reusing of the type casting mechanism lets other parties provide rehydration that performs arbitrarily complex operations.

We provide built-in rehydration for some of PowerShell types… :

… as well as for some types from base class libraries:

Thanks,

Lukasz Anforowicz [MSFT]
Windows PowerShell Developer
Microsoft Corporation

Leave a Comment
  • Please add 6 and 3 and type the answer here:
  • Post
  • I can see why it works that way, and it's good enough to be very useful, but wouldn't it be nice if the remote object could somehow (e.g. using some kind of proxy object) be sent live to the local session?  We would be able to call methods and have them execute on the remote computer, or receive events from the remote computer, all transparently.

  • This is all well and nice, but how am I supposed to use PowerShell within C# to gain access to properties that aren't primitives?

    I'm working with Exchange 2010 and I need to use Get-MailboxStatistics for the TotalItemSize, which is an Unlimited<long> (a type in Microsoft.Exchange.Data).

    I can use .Properties["TotalItemSize"], but that gives me a string that is less than practical to parse. (e.g. "22.01K (22,704 bytes)")

    Are there other ways to call PowerShell from C# that will let me access the types properly? I have access to the Microsoft.Exchange.Data.* DLLs files with all the types in there.

  • I can not get the value of 'Mounted' property when i using PSSession via C#/.net.

    command.AddScript("Invoke-Command -ScriptBlock { Get-MailboxDatabase -Status }" + " -Session $myVar");

    I can get the result after invoking the command,but the value of the 'Mounted' property is null!

  • Like the person above I can't get the Mounted property returned when I invoke the Get-MailboxDatabase command from C#.  I can see all sorts of other properties, but not Mounted.  What's going on?

  • Pat, use the -Status parameter to get the mounted status for a DB.

Page 1 of 1 (5 items)