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

如何将PowerShell返回结果映射到C#自定义类?

问题解决:PowerShell结果映射到C#自定义类及Get-Service无返回问题

问题描述

  1. PowerShell返回的嵌套哈希表(如Res1)无法正确解析为C#自定义类属性,当前仅能存储为字符串格式,无法提取具体字段(如Used、Free)。
  2. 调用Get-Service查询服务信息时,C#端无返回结果,但直接在PowerShell中执行可正常获取数据。
  3. 目标是将PowerShell结果映射到如下自定义类:
public class MyClass
{
    public string ComputerName { get; set; }
    public string CUsedSpace { get; set; }
    public string CFreeSpace { get; set; }
    public string DUsedSpace { get; set; }
    public string DFreeSpace { get; set; }
    public List<string> FolderGroup1Names { get; set; }
    public List<string> FolderGroup2Names { get; set; }
}

解决方法

一、嵌套哈希表解析到自定义类

1. 修改PowerShell脚本,返回扁平化对象

避免返回嵌套哈希表,直接构造包含所有所需字段的PSCustomObject,让C#端无需解析嵌套结构:

$computers = @"
Server1
"@ -split [Environment]::NewLine

$oRes1 = Invoke-Command -ComputerName $computers {
    $cDrive = Get-PSDrive C | Select-Object Used,Free
    $dDrive = Get-PSDrive D | Select-Object Used,Free
    $folderGroup1 = Get-ChildItem "c:\temp" | Select-Object -ExpandProperty Name
    $folderGroup2 = Get-ChildItem "d:\temp" | Select-Object -ExpandProperty Name

    [PSCustomObject]@{
        ComputerName = hostname
        CUsedSpace = $cDrive.Used
        CFreeSpace = $cDrive.Free
        DUsedSpace = $dDrive.Used
        DFreeSpace = $dDrive.Free
        FolderGroup1Names = $folderGroup1
        FolderGroup2Names = $folderGroup2
    }
}

$oRes1

2. C#端直接映射到MyClass

利用PowerShell的Invoke<T>()方法自动映射属性(需确保属性名完全匹配,大小写不敏感):

using System.Collections.Generic;
using System.Management.Automation;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            List<MyClass> computers;

            using (PowerShell ps = PowerShell.Create())
            {
                ps.AddScript(@"
$computers = @""
Server1
""@ -split [Environment]::NewLine

$oRes1 = Invoke-Command -ComputerName $computers {
    $cDrive = Get-PSDrive C | Select-Object Used,Free
    $dDrive = Get-PSDrive D | Select-Object Used,Free
    $folderGroup1 = Get-ChildItem ""c:\temp"" | Select-Object -ExpandProperty Name
    $folderGroup2 = Get-ChildItem ""d:\temp"" | Select-Object -ExpandProperty Name

    [PSCustomObject]@{
        ComputerName = hostname
        CUsedSpace = $cDrive.Used
        CFreeSpace = $cDrive.Free
        DUsedSpace = $dDrive.Used
        DFreeSpace = $dDrive.Free
        FolderGroup1Names = $folderGroup1
        FolderGroup2Names = $folderGroup2
    }
}

$oRes1
");

                // 直接映射到MyClass
                computers = ps.Invoke<MyClass>().ToList();
            }

            // 验证结果
            foreach (var computer in computers)
            {
                System.Console.WriteLine($"计算机名: {computer.ComputerName}");
                System.Console.WriteLine($"C盘已用: {computer.CUsedSpace}");
                System.Console.WriteLine($"C盘剩余: {computer.CFreeSpace}");
            }
        }
    }

    public class MyClass
    {
        public string ComputerName { get; set; }
        public string CUsedSpace { get; set; }
        public string CFreeSpace { get; set; }
        public string DUsedSpace { get; set; }
        public string DFreeSpace { get; set; }
        public List<string> FolderGroup1Names { get; set; }
        public List<string> FolderGroup2Names { get; set; }
    }
}

如果必须保留原PowerShell的嵌套结构,可手动解析嵌套PSObject:

// 原脚本不变的情况下,手动解析Res1
foreach (var outputObject in result)
{
    var cDrive = outputObject.Properties["Res1"].Value as PSObject;
    var dDrive = outputObject.Properties["Res2"].Value as PSObject;
    var folderGroup1 = (outputObject.Properties["Res4"].Value as IEnumerable<PSObject>)?.Select(p => p.Properties["Name"].Value.ToString()).ToList();
    var folderGroup2 = (outputObject.Properties["Res5"].Value as IEnumerable<PSObject>)?.Select(p => p.Properties["Name"].Value.ToString()).ToList();

    computers.Add(new MyClass()
    {
        ComputerName = outputObject.Properties["Res3"].Value.ToString(),
        CUsedSpace = cDrive?.Properties["Used"].Value.ToString(),
        CFreeSpace = cDrive?.Properties["Free"].Value.ToString(),
        DUsedSpace = dDrive?.Properties["Used"].Value.ToString(),
        DFreeSpace = dDrive?.Properties["Free"].Value.ToString(),
        FolderGroup1Names = folderGroup1,
        FolderGroup2Names = folderGroup2
    });
}

二、Get-Service无返回问题解决

1. 检查PowerShell执行错误

先排查是否有错误输出,在C#中添加错误日志:

using (PowerShell ps = PowerShell.Create())
{
    ps.AddScript(@"
$computers = @""
Server1
""@ -split [Environment]::NewLine
Invoke-Command -ComputerName $computers {
    Get-Service -Name *ssp* | Select-Object Name, Status, PSComputerName, StartType
}
");

    var services = ps.Invoke<SspService>().ToList();

    // 检查错误
    if (ps.Streams.Error.Count > 0)
    {
        foreach (var error in ps.Streams.Error)
        {
            System.Console.WriteLine($"PowerShell错误: {error.ToString()}");
        }
    }
}

2. 确保属性映射匹配

StartType在PowerShell中是枚举类型,C#端需用对应类型或字符串接收;另外,Status也是枚举,可直接转字符串:

public class SspService
{
    public string? Name { get; set; }
    public string? Status { get; set; }
    public string? PSComputerName { get; set; }
    public string? StartType { get; set; }
}

3. 显式返回PSCustomObject

如果自动映射失效,可在PowerShell中显式构造对象,确保字段名完全匹配:

Invoke-Command -ComputerName $computers {
    Get-Service -Name *ssp* | ForEach-Object {
        [PSCustomObject]@{
            Name = $_.Name
            Status = $_.Status.ToString()
            PSComputerName = $_.PSComputerName
            StartType = $_.StartType.ToString()
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:02:06