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

时间:2010-02-25 00:08:12

标签: c# .net powershell powershell-sdk

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

例如:

我有一个调用WriteObject的cmdlet,并在管道中推送一个ClassXzy集合。当我从主机端调用PowerShell.Invoke时,我会检索PSObjectBaseObject属性的集合。将BaseObject投射到ClassXyz失败。

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

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

有什么想法吗?

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

3 个答案:

答案 0 :(得分:10)

在你提到反序列化过程之前,基思回答了你的问题。

至于序列化/反序列化

我怀疑是否有可能获得原始对象。我不知道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()返回的信息不再反映日期更改 - 它是冻结值。

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

答案 1 :(得分:3)

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

答案 2 :(得分:0)

您可以执行上述操作,但是一旦PSRemoting发挥作用,这些方法都会崩溃,因为您将访问代理对象。最好的做法是使用PSMembers&amp; amp; PSProperties