自定义PowerShell主机和将PSObject转换回基础类型

14
当托管 PowerShell 运行时时,有没有可能将 PSObject 转换回其原始类型呢?
例如:
我有一个 cmdlet 调用 WriteObject 并在管道中推送 ClassXzy 集合。 当我从主机端调用 PowerShell.Invoke 时,我会检索到一组具有 BaseObject 属性的 PSObjects 集合。 将 BaseObject 强制转换为 ClassXyz 失败。
是否有任何方法可以绕过将每个属性值映射到其对应的原始对象? 我假设 PowerShell 以某种方式执行此操作,因为您可以将 PSObjects 传递给 cmdlet,并将其转换为参数类型。 但是如何实现?
我花了很长时间用 Reflector 深入挖掘 PS 程序集,但还没有真正确定这种黑科技是如何实现的。
有什么想法吗?
编辑:我忘记了一个非常重要的细节。 我正在测试的 PSObject 是远程对象,因此 BaseObject 类型被命名为 Deserialized.ClassXyz。 这就是为什么我看到如此奇怪的行为。
3个回答

10

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

关于序列化/反序列化

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

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

请尝试此示例:

$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

  • 将继承层级变平了。
  • 只“实现”属性,
  • 并且因为它知道ToString()方法的值,所以它也可以将该方法的结果添加进去。但是你可以看到从ToString()返回的信息不再反映日期的变化 - 它是冻结的值。

考虑到上述内容,我在远程序列化、通过Export-CliXml进行的clixml序列化或使用Receive-Job时没有看到任何区别,所以我认为在这两种情况下都是不可能的。


是的,我的思维过程中存在缺陷,我完全忘记了远程传输部分!在管道的另一端没有办法拥有一个实时对象是有道理的。感谢您提供的好例子。 - Adam Driscoll

4

您可以访问PSObject上的BaseObject属性(它会遍历每个PSObject,直到找到实际的基本对象),或者使用ImmediateBaseObject,它只获取链中的下一个对象。


我忘记了一些非常重要的事情。PSObject 来自远程操作。请查看我的更新问题以获取更多详细信息。您的答案确实适用于本地操作。 - Adam Driscoll
2
PowerShell 远程管理使用 WSMan/SOAP 协议,因此它不会“远程”实时对象。你所获得的“反序列化.*”对象只是一个属性包,没有与原始对象的连接。 - Keith Hill
谢谢。远程因素完全改变了这个问题! - Adam Driscoll

0

你可以按照上述方法进行操作,但是一旦使用PSRemoting,这些方法都会失效,因为你将访问代理对象。最佳实践是使用PSMembers和PSProperties。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接