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

Viewed 834

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        : Tester_IA@contoso.com
AddressString      : Tester_IA@contoso.com
ProxyAddressString : smtp:Tester_IA@contoso.com
Prefix             : SMTP
IsPrimaryAddress   : False
PrefixString       : smtp

SmtpAddress        : TesterIA@contoso.com
AddressString      : TesterIA@contoso.com
ProxyAddressString : SMTP:TesterIA@contoso.com
Prefix             : SMTP
IsPrimaryAddress   : True
PrefixString       : SMTP

SmtpAddress        : TesterIA@outlook.contoso.com
AddressString      : TesterIA@outlook.contoso.com
ProxyAddressString : smtp:TesterIA@outlook.contoso.com
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:Tester_IA@contoso.com
SMTP:TesterIA@contoso.com
smtp:TesterIA@outlook.contoso.com

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

2 Answers

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.

Related