-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()
表示。
当我在 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()
代表所取代.
- 实际上,这意味着 非知名(标量)类型的实例序列化使得 属性 本身不是知名类型实例的值 被他们的
请参阅
适用于您的情况:
通过远程处理,最初包含在 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()
表示。