如何通过PowerShell SDK在C#中访问PowerShell对象的值?
问题:C# Windows服务调用PowerShell仅输出对象类型而非实际值
问题背景
我是C#与.NET编程新手,正在将一段PowerShell脚本转换为功能等效的Windows服务代理。该代理编译、安装正常,可将PowerShell命令输出写入日志文件,但日志仅打印对象类型而非实际值,需要解决如何正确访问PowerShell对象中的值的问题。
相关代码示例(错误写法)
using System.Management.Automation; using System.IO; using System; // Windows服务中调用PowerShell的核心代码 public void ExecutePowerShellCommand() { using (var ps = PowerShell.Create()) { ps.AddCommand("Get-Service") .AddParameter("Name", "WinRM"); var results = ps.Invoke(); // 错误:直接ToString()仅输出对象类型 foreach (var result in results) { File.AppendAllText(@"C:\service.log", result.ToString() + Environment.NewLine); } } }
日志输出示例
System.Management.Automation.PSCustomObject
原PowerShell脚本
# 原脚本:获取指定服务的名称与状态 Get-Service -Name WinRM | Select-Object Name, Status, StartType
解决方案
1. 直接访问对象属性(推荐)
PowerShell返回的是PSCustomObject实例,可通过Properties集合或dynamic类型直接读取属性值:
方式1:使用Properties集合(类型安全)
foreach (var result in results) { // 读取属性值,需先检查属性是否存在 var serviceName = result.Properties.ContainsKey("Name") ? result.Properties["Name"].Value : "N/A"; var serviceStatus = result.Properties.ContainsKey("Status") ? result.Properties["Status"].Value : "N/A"; var startType = result.Properties.ContainsKey("StartType") ? result.Properties["StartType"].Value : "N/A"; File.AppendAllText(@"C:\service.log", $"服务名称: {serviceName}, 状态: {serviceStatus}, 启动类型: {startType}{Environment.NewLine}"); }
方式2:使用dynamic类型(简化代码)
foreach (dynamic result in results) { // 直接通过属性名访问,需确保属性存在 string serviceName = result.Name; string serviceStatus = result.Status.ToString(); string startType = result.StartType.ToString(); File.AppendAllText(@"C:\service.log", $"服务名称: {serviceName}, 状态: {serviceStatus}, 启动类型: {startType}{Environment.NewLine}"); }
2. 获取PowerShell格式化输出(与控制台一致)
如果需要和PowerShell控制台输出完全相同的文本格式,可在脚本中添加Out-String命令:
using (var ps = PowerShell.Create()) { // 原脚本末尾添加Out-String,将对象转换为格式化文本 ps.AddScript(@"Get-Service -Name WinRM | Select-Object Name, Status, StartType | Out-String"); var results = ps.Invoke(); foreach (var result in results) { File.AppendAllText(@"C:\service.log", result.ToString() + Environment.NewLine); } }
3. 处理空值与错误
调用PowerShell时需处理可能的空结果或错误,避免空引用异常:
using (var ps = PowerShell.Create()) { ps.AddCommand("Get-Service") .AddParameter("Name", "WinRM"); var results = ps.Invoke(); // 处理错误流 if (ps.Streams.Error.Count > 0) { foreach (var error in ps.Streams.Error) { File.AppendAllText(@"C:\service.log", $"错误: {error.Message}{Environment.NewLine}"); } } // 处理空结果 if (results.Count == 0) { File.AppendAllText(@"C:\service.log", "未找到指定服务" + Environment.NewLine); return; } // 读取属性值 foreach (var result in results) { var serviceName = result.Properties["Name"]?.Value ?? "N/A"; File.AppendAllText(@"C:\service.log", $"服务名称: {serviceName}{Environment.NewLine}"); } }
原因说明
PowerShell命令返回的是.NET对象(如PSCustomObject),直接调用ToString()方法默认返回对象的类型名称,而非对象的属性内容。必须显式访问对象的属性,或通过Out-String将对象转换为格式化文本,才能获取实际业务值。
内容的提问来源于stack exchange,提问作者Patrick Carra
相关产品推荐
相关产品推荐

