-ExpandProperty doesn't show all the properties via Remote PowerShell
Asked Answered
G

2

4

When I run the following code in Exchange PowerShell on an Exchange server it shows all the properties:

PS> Get-Mailbox Testeria | select -ExpandProperty EmailAddresses

SmtpAddress        : [email protected]
AddressString      : [email protected]
ProxyAddressString : smtp:[email protected]
Prefix             : SMTP
IsPrimaryAddress   : False
PrefixString       : smtp

SmtpAddress        : [email protected]
AddressString      : [email protected]
ProxyAddressString : SMTP:[email protected]
Prefix             : SMTP
IsPrimaryAddress   : True
PrefixString       : SMTP

SmtpAddress        : [email protected]
AddressString      : [email protected]
ProxyAddressString : smtp:[email protected]
Prefix             : SMTP
IsPrimaryAddress   : False
PrefixString       : smtp

But when I try to use Remote PowerShell on the local machine via

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri ("http://" + $Server + "/PowerShell/") -Authentication Kerberos
Import-PSSession $Session

and run the same code it show only this:

PS> Get-Mailbox Testeria | select -ExpandProperty EmailAddresses

smtp:[email protected]
SMTP:[email protected]
smtp:[email protected]

How to understand this behaviour? How to get all the properties via Remote PowerShell?

PSVersion on the local machine is 5.1.14409.1005

PSVersion on the Exchange Server is 4.0

Guimar answered 29/6, 2017 at 12:19 Comment(0)
C
3

This probably occurs because when you access objects via PSRemoting the results are deserialized. You can see this is the case by looking at the TypeName of the resulting object by pipling it to Get-Member. You will see Deserialized prefixed to the Type:

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).

My assumption is that the EmailAddresses property is a Script Property, which means it executes a script when called to get its sub properties. When you retrieve the object via Remoting you lose the ability to execute this script.

Unfortunately I don't have an Exchange system to verify this on at the moment.

Cajole answered 29/6, 2017 at 12:23 Comment(1)
Good pointers, but I think the real reason the EmailAddresses objects turn to strings is the implicit recursion-depth limit that the remoting infrastructure applies to non-well-known (scalar) objects, which replaces property values that aren't themselves instance of well-known types with their .ToString() values.Candlemas
C
1

Mark Wragg's answer provides helpful pointers, but let me elaborate:

  • Objects transmitted via PowerShell's remoting infrastructure undergo XML-based serialization at the remote source, and deserialization on receipt by the caller.

  • With the exception of a select few well-known types, type fidelity is lost during serialization / deserialization, and the deserialized objects are emulations of the original objects, as indicated by the Deserialized. prefix in their type name (as you can see by accessing .pstypenames[0] on a deserialized instance of by piping it to Get-Member); specifically, the limitation of these emulations - beyond not having the same type identity as the originals - are:

    • Deserialized objects lack the methods of the original.
    • For nested (scalar) objects (objects composed of multiple properties whose values too are objects composed of multiple properties, ...), the object graph is limited to a depth of 1.
      • In practice, this means that instances of non-well-known (scalar) types serialize such that property values that aren't themselves instances of well-known types are replaced by their .ToString() representations.

See this answer for a more comprehensive overview of serialization as part of PowerShell's remoting infrastructure.


Applied to your case:

Via remoting, the collection of rich email-object instances originally contained in the .EmailAddresses property of the objects returned by the Get-MailBox cmdlet is converted to a collection of strings, by calling .ToString() on each email-object instance, which seemingly returns the .ProxyAddressString property value.


Example:

For simplicity, the following demonstrates the recursion-depth (stringification) problem via a local background job created with Start-Job call (background jobs also use PowerShell's remoting infrastructure):

PS> Start-Job { 
      # Define a custom class, which is by definition not a well-known type.
      # Give it a property of another non-well-known type, [regex].
      class Foo { $Bar = [regex] 'hi' }
      # Output an instance of the custom class.
      [Foo]::new() 
    } | Receive-Job -Wait -AutoRemove | 
        ForEach-Object {
          $_.Bar                     # Output the .Bar property value...
          $_.Bar.GetType().FullName  # ... and its data type.
        }

hi
System.String

As you can see, the [regex] instance stored in property .Bar was replaced by its .ToString() representation.

Candlemas answered 2/6, 2021 at 15:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.