.NET Framework Windows服务中PowerShell.Invoke<T>类型参数推断失败问题
.NET Framework Windows服务中调用PowerShell脚本出现类型推断错误
我有一个.NET Framework Windows服务项目,需要在其中运行PowerShell脚本。相同代码在控制台应用中运行正常,但在服务项目中报错:无法从用法中推断方法‘PowerShell.Invoke
代码如下:
private Thread workerThread; private bool running; private static readonly ILog log = LogManager.GetLogger(typeof(Service1)); public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { running = true; workerThread = new Thread(WorkerThreadProc); workerThread.Start(); } protected override void OnStop() { running = false; workerThread.Join(); } private static void WorkerThreadProc() { bool running = true; using (var runspace = RunspaceFactory.CreateRunspace()) { runspace.Open(); while (running) { try { string powerShellCommand = "Get-Process"; string output = RunPowerShellCommand(powerShellCommand); string directoryPath = @"C:\HttpConnector\Output"; string fileName = "PsOutput.txt"; string filePath = Path.Combine(directoryPath, fileName); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } WriteToFile(filePath, output); } catch (Exception ex) { log.Error("Hata oluştu.", ex); } TimeSpan interval = TimeSpan.FromMinutes(1); Thread.Sleep(interval); } runspace.Close(); } } private static string RunPowerShellCommand(string command) { using (var runspace = RunspaceFactory.CreateRunspace()) { runspace.Open(); using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddScript(command); try { var results = ps.Invoke(); var output = GetObjectInfo(results); return output; } catch (Exception ex) { log.Error("Hata oluştu: " + ex.ToString()); return string.Empty; } } } } private static string GetObjectInfo(Collection<PSObject> psObjects) { string output = string.Empty; foreach (var psObject in psObjects) { output += $"{psObject.ToString()}{Environment.NewLine}"; } return output; }
已安装的NuGet包:
- Microsoft.PowerShell.SDK
- System.Management.Automation
问题原因与解决方法
原因分析
Windows服务的运行上下文对编译器类型推断的限制比控制台应用更严格,导致无法自动识别PowerShell.Invoke<T>()的泛型参数类型,而控制台应用环境的类型推断规则更宽松,因此未触发该错误。
解决步骤
- 显式指定泛型参数:将
ps.Invoke()修改为ps.Invoke<PSObject>(),明确告知编译器返回类型为Collection<PSObject>,与后续GetObjectInfo方法的参数类型匹配。 - 修复线程循环停止问题:
WorkerThreadProc中的局部running变量会导致服务停止时循环无法终止,需改为使用类级别的running字段。
修改后的关键代码
修正后的RunPowerShellCommand方法
private static string RunPowerShellCommand(string command) { using (var runspace = RunspaceFactory.CreateRunspace()) { runspace.Open(); using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddScript(command); try { // 显式指定泛型参数PSObject var results = ps.Invoke<PSObject>(); var output = GetObjectInfo(results); return output; } catch (Exception ex) { log.Error("发生错误: " + ex.ToString()); return string.Empty; } } } }
修正后的WorkerThreadProc方法
private void WorkerThreadProc() { using (var runspace = RunspaceFactory.CreateRunspace()) { runspace.Open(); while (running) // 使用类成员变量替代局部变量 { try { string powerShellCommand = "Get-Process"; string output = RunPowerShellCommand(powerShellCommand); string directoryPath = @"C:\HttpConnector\Output"; string fileName = "PsOutput.txt"; string filePath = Path.Combine(directoryPath, fileName); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } WriteToFile(filePath, output); } catch (Exception ex) { log.Error("发生错误.", ex); } TimeSpan interval = TimeSpan.FromMinutes(1); Thread.Sleep(interval); } runspace.Close(); } }
内容的提问来源于stack exchange,提问作者mgk
相关产品推荐
相关产品推荐

