How objects are sent to and from remote sessions

PowerShell Team

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

0 comments

Discussion is closed.

Feedback usabilla icon