-ExpandProperty 不通过 Remote PowerShell 显示所有属性

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

当我在 Exchange 服务器上的 Exchange PowerShell 中 运行 以下代码时,它会显示所有属性:

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

但是当我尝试通过

在本地计算机上使用 Remote PowerShell 时
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri ("http://" + $Server + "/PowerShell/") -Authentication Kerberos
Import-PSSession $Session

和 运行 相同的代码只显示了这个:

PS> Get-Mailbox Testeria | select -ExpandProperty EmailAddresses

smtp:Tester_IA@contoso.com
SMTP:TesterIA@contoso.com
smtp:TesterIA@outlook.contoso.com

如何理解这种行为?如何通过 Remote PowerShell 获取所有属性?

本地机器上的 PSVersion 是 5.1.14409.1005

Exchange 服务器上的 PSVersion 是 4.0

这可能是因为当您通过 PSRemoting 访问对象时,结果被反序列化。通过将结果对象的 TypeName 管道化为 Get-Member,您可以看到这种情况。你会看到 Deserialized 前缀为 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).

我的假设是 EmailAddresses 属性 是一个脚本 属性,这意味着它在调用以获取其子属性时执行脚本。当您通过 Remoting 检索对象时,您将失去执行此脚本的能力。

很遗憾,我目前没有 Exchange 系统来验证这一点。

提供了有用的指示,但让我详细说明一下:

  • 通过 PowerShell 的 remoting 基础设施 传输的对象在远程源,以及 反序列化 由调用者接收。

  • 除了 select 少数 众所周知的 类型外, 类型保真度丢失在序列化/反序列化期间,反序列化的对象是原始对象仿真,如Deserialized. 类型名称中的前缀(正如您可以通过在反序列化实例上访问 .pstypenames[0] 将其管道化到 Get-Member 所见);具体来说,这些模拟的局限性 - 除了不具有与原件相同的 类型身份 - 是:

    • 反序列化的对象缺少原始的方法
    • 对于嵌套(标量)对象(由多个属性组成的对象,其值也是由多个属性组成的对象,...),对象图被限制在一个深度1 个。
      • 实际上,这意味着 非知名(标量)类型的实例序列化使得 属性 本身不是知名类型实例的值 被他们的 .ToString() 代表所取代.

请参阅 以更全面了解序列化 作为 PowerShell 远程处理基础结构的一部分。


适用于您的情况

通过远程处理,最初包含在 Get-MailBox cmdlet 返回的对象的 .EmailAddresses 属性 中的富电子邮件对象实例的集合被转换为 strings,通过在每个电子邮件对象实例上调用 .ToString(),这看似 returns .ProxyAddressString 属性 值。


示例

为简单起见,下面通过使用 Start-Job 调用创建的本地后台作业演示递归深度(字符串化)问题(后台作业也使用 PowerShell 的远程处理基础结构):

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

如您所见,存储在 属性 .Bar 中的 [regex] 实例已替换为它的 .ToString() 表示。