如何在C# WinForms应用中定时执行PowerShell脚本并展示结果
解决方案
1. 添加PowerShell依赖
要在C#中执行PowerShell脚本,首先需要添加System.Management.Automation程序集的引用。你可以通过NuGet包管理器安装Microsoft.PowerShell.SDK来获取这个依赖。
2. 在Timer Tick事件中集成PowerShell执行逻辑
修改你的timer1_Tick方法,加入PowerShell脚本的执行和结果处理逻辑:
private void timer1_Tick(object sender, EventArgs e) { string psCommand = @"Get-Service -ComputerName ""DESKTOP"" -Name ""WinDefend"""; try { using (PowerShell psInstance = PowerShell.Create()) { psInstance.AddScript(psCommand); var results = psInstance.Invoke(); // 处理执行结果 if (results.Any()) { var serviceInfo = results[0].BaseObject as ServiceController; if (serviceInfo != null) { string statusContent = $"[{DateTime.Now:HH:mm:ss}] 服务器DESKTOP的WinDefend服务状态:{serviceInfo.Status}"; UpdateUi(statusContent); } } else { UpdateUi($"[{DateTime.Now:HH:mm:ss}] 无法获取WinDefend服务状态:未找到服务或远程连接失败"); } // 处理执行过程中的错误 if (psInstance.Streams.Error.Any()) { string errorMsg = $"[{DateTime.Now:HH:mm:ss}] 执行错误:{psInstance.Streams.Error[0].Exception.Message}"; UpdateUi(errorMsg); } } } catch (Exception ex) { UpdateUi($"[{DateTime.Now:HH:mm:ss}] 异常:{ex.Message}"); } }
3. 安全更新UI控件
WinForms控件只能在创建它的UI线程中更新,因此需要封装一个跨线程安全的更新方法,同时支持TextBox和Label的显示需求:
private void UpdateUi(string content) { // 检查是否需要跨线程调用 if (textBoxStatus.InvokeRequired) { textBoxStatus.Invoke(new Action<string>(UpdateUi), content); return; } // 更新TextBox:追加历史监控记录 textBoxStatus.AppendText(content + Environment.NewLine); // 自动滚动到最新内容 textBoxStatus.ScrollToCaret(); // 更新Label:仅显示最新的监控状态 labelLatestStatus.Text = content; }
4. 扩展到多服务器多服务
如果要监控多台服务器的多个服务,可以预先定义监控目标列表,在Tick事件中批量执行:
// 定义监控目标,可根据实际需求修改 private readonly List<(string ServerName, string ServiceName)> _monitorList = new() { ("DESKTOP", "WinDefend"), ("SERVER-01", "Spooler"), ("SERVER-02", "TermService") }; // 修改后的Tick事件 private void timer1_Tick(object sender, EventArgs e) { foreach (var target in _monitorList) { string psCommand = $"Get-Service -ComputerName ""{target.ServerName}"" -Name ""{target.ServiceName}"""; ExecutePsCommandAndUpdateUi(psCommand); } } // 封装复用的执行方法 private void ExecutePsCommandAndUpdateUi(string psCommand) { try { using (PowerShell psInstance = PowerShell.Create()) { psInstance.AddScript(psCommand); var results = psInstance.Invoke(); if (results.Any()) { var service = results[0].BaseObject as ServiceController; if (service != null) { string content = $"[{DateTime.Now:HH:mm:ss}] 服务器{service.MachineName}的{service.ServiceName}服务状态:{service.Status}"; UpdateUi(content); } } else { // 从命令中解析服务器和服务名 string[] parts = psCommand.Split(new[] { "-ComputerName", "-Name" }, StringSplitOptions.RemoveEmptyEntries); string server = parts[1].Trim('"', ' '); string service = parts[2].Trim('"', ' '); UpdateUi($"[{DateTime.Now:HH:mm:ss}] 无法获取服务器{server}的{service}服务状态"); } if (psInstance.Streams.Error.Any()) { UpdateUi($"[{DateTime.Now:HH:mm:ss}] 执行错误:{psInstance.Streams.Error[0].Exception.Message}"); } } } catch (Exception ex) { UpdateUi($"[{DateTime.Now:HH:mm:ss}] 异常:{ex.Message}"); } }
关键注意事项
- 权限要求:运行程序的账号必须拥有远程服务器的服务访问权限,否则会出现权限不足的错误。
- UI性能:如果监控目标较多,建议将PowerShell执行逻辑放到异步任务中(比如用
Task.Run),避免阻塞UI线程导致界面卡顿。 - 异常处理:务必处理网络中断、服务不存在、权限不足等各种异常场景,保证监控应用的稳定性。
内容的提问来源于stack exchange,提问作者Stefan Meeuwessen
相关产品推荐
相关产品推荐

