自定义PowerShell主机并将PSObject转换回基本类型

托管PowerShell运行时是否可以将PSObject转换回其原始类型?

例如:

我有一个cmdlet调用WriteObject并在管道中推送一个ClassXzy集合。 当我从主机端调用PowerShell.Invoke时,我检索了一个带有BaseObject属性的PSObject集合。 将BaseObjectClassXyz失败。

有没有办法将每个属性值映射到其对应的原始对象?
我假设PowerShell以某种方式执行此操作,因为您可以将PSObject传递给cmdlet并将它们转换为参数类型。 但是怎么样?

我花时间用reflection器撕裂了PS组件,但还没有真正确定这种魔法是如何发生的。

有任何想法吗?

编辑:我忘记了一个非常重要的细节。 我正在测试的PSObject是一个远程对象,因此BaseObject类型被命名为Deserialized.ClassXyz 。 这就是为什么我看到这种奇怪的行为。

在您提到反序列化过程之前,Keith回答了您的问题。

至于序列化/反序列化

我怀疑是否有可能获得原始对象。 我不知道PowerShell使用什么类型的序列化,但是如果你考虑简单的Xml序列化,那么你可以意识到你只能序列化属性而不是其他任何东西。
您无法序列化其方法的bodys。
你不能序列化它的所有事件的订阅者(或者在某些情况下可能会有可能,但我不是这样的.NET专家)。
并且因为类型(如我的示例中)可能不可用(例如,组件仅存在于远程计算机上),所以需要传输所有类型信息。

它不仅涉及类型,还涉及对象实现的所有inheritance层次结构和接口。 它们也会以某种方式被序列化。

试试这个例子:

 $deserialized = Start-Job { Add-Type -TypeDefinition @" public class Parent { public override string ToString() { return "overriden parent"; } public int IntParent { get { return 1; } } } public class TestClass : Parent { public string GString() { return "this is a test string"; } public override string ToString() { return "overriden tostring" + System.DateTime.Now.ToString(); } public int IntProp { get { return 3451; } } } "@ New-Object TestClass } | Wait-Job | Receive-Job $deserialized.ToString() $deserialized | gm -for 

你会看到,PowerShell

  • 展平inheritance层次结构。
  • ‘实现’只有属性
  • 并且因为它知道ToString()的值,所以它也可以添加方法的结果。 但正如您所看到的,从ToString()返回的信息不再反映日期更改 – 它是冻结值。

我没有看到远程处理的序列化,clixml的序列化(通过Export-CliXml )或者在考虑我上面写的内容时的Receive-Job之间没有任何区别,因此我认为在这两种情况下都是不可能的。

您可以访问BaseObject上的BaseObject属性(它会遍历每个PSObject,直到它到达实际的基础对象)或者刚刚抓取链中下一个对象的ImmediateBaseObject

您可以执行上面描述的操作,但是一旦PSRemoting发挥作用,这些方法都会崩溃,因为您将访问代理对象。 最佳实践是使用PSMembers和PSProperties