如何将PowerShell返回结果映射到C#自定义类?
问题解决:PowerShell结果映射到C#自定义类及Get-Service无返回问题
问题描述
- PowerShell返回的嵌套哈希表(如Res1)无法正确解析为C#自定义类属性,当前仅能存储为字符串格式,无法提取具体字段(如Used、Free)。
- 调用
Get-Service查询服务信息时,C#端无返回结果,但直接在PowerShell中执行可正常获取数据。 - 目标是将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
相关产品推荐
相关产品推荐

