You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#的进程外Runspace中获取PowerShell完整对象?

在C#进程外Runspace中获取PowerShell返回的完整对象

我明白你遇到的问题了——用进程外Runspace跑PowerShell脚本时,返回的复杂类型(比如Get-Process的结果)只能拿到类型名称,没法访问内部成员,但同进程Runspace就没问题。这本质上是因为跨进程通信时,.NET对象不能直接传递,默认的序列化只保留了类型信息,没有序列化对象的实际数据。下面给你两种可行的解决办法:

方法1:使用PowerShell内置序列化机制

PowerShell自带[System.Management.Automation.PSSerializer]类,专门处理PowerShell对象的序列化与反序列化,能完整保留对象的所有成员信息,跨进程传递后再还原回来。

修改后的C#代码示例:

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

class Program
{
    static void Main()
    {
        using (var run = RunspaceFactory.CreateOutOfProcessRunspace(null))
        {
            run.Open();
            using (PowerShell ps = PowerShell.Create())
            {
                ps.Runspace = run;
                // 在PowerShell脚本中序列化对象为XML格式
                ps.AddScript(@"
                    $processes = Get-Process
                    [System.Management.Automation.PSSerializer]::Serialize($processes)
                ");
                // 获取序列化后的XML字符串
                var serializedXml = ps.Invoke()[0].ToString();
                
                // 在C#中反序列化回PSObject集合
                var processes = (System.Collections.ObjectModel.Collection<PSObject>)
                    PSSerializer.Deserialize(serializedXml);
                
                // 现在可以正常访问对象的所有成员了
                foreach (var proc in processes)
                {
                    Console.WriteLine($"进程名: {proc.Properties["ProcessName"].Value}, ID: {proc.Properties["Id"].Value}");
                }
            }
        }
    }
}

方法2:通过JSON格式传递对象

如果更熟悉JSON,也可以用PowerShell的ConvertTo-Json cmdlet把对象序列化为JSON字符串,再在C#中用JSON库反序列化。注意要指定足够的-Depth参数,避免嵌套对象被截断。

示例代码:

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text.Json;

class Program
{
    static void Main()
    {
        using (var run = RunspaceFactory.CreateOutOfProcessRunspace(null))
        {
            run.Open();
            using (PowerShell ps = PowerShell.Create())
            {
                ps.Runspace = run;
                // 转换为JSON,设置深度确保完整序列化
                ps.AddScript("Get-Process | ConvertTo-Json -Depth 10");
                var jsonString = ps.Invoke()[0].ToString();
                
                // 反序列化为动态对象(也可以定义对应实体类)
                var processes = JsonSerializer.Deserialize<dynamic>(jsonString);
                
                foreach (var proc in processes)
                {
                    Console.WriteLine($"进程名: {proc.ProcessName}, ID: {proc.Id}");
                }
            }
        }
    }
}

为什么同进程Runspace没有这个问题?

因为同进程中,Invoke()返回的对象是直接在当前进程内存中的实例,不需要经过序列化/反序列化步骤,所以能直接访问所有成员。而进程外Runspace是跨进程通信,必须通过序列化把对象转换成可传递的格式,默认的返回结果只是序列化后的“壳”(仅包含类型信息),所以需要我们显式处理序列化过程才能拿到完整数据。

内容的提问来源于stack exchange,提问作者usr1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:54:38