如何在C# WinForm中异步调用远程服务器的多个PowerShell脚本
异步改造实现方案
你可以将原同步方法改造为符合.NET TAP异步任务模型的实现,适配WinForm场景不会阻塞UI线程,改造后的代码如下:
public async Task<string> NewPsSessionAsync(string ServerName, string command) { // 使用using自动管理资源生命周期,避免手动释放遗漏 using Runspace runspace = RunspaceFactory.CreateRunspace(); runspace.Open(); using PowerShell psSession = PowerShell.Create(); psSession.Commands.AddScript("$sessions = New-PSSession -ComputerName " + ServerName + Environment.NewLine + "Invoke-Command -session $sessions -ScriptBlock {" + command + "}" + Environment.NewLine + "Remove-PSSession -Session $sessions" + Environment.NewLine); psSession.Commands.AddCommand("Out-String"); Collection<PSObject> results = new Collection<PSObject>(); try { // 把PowerShell原生APM异步模式转为TAP模式,支持async/await调用 results = await Task.Factory.FromAsync(psSession.BeginInvoke(), psSession.EndInvoke); } catch (Exception ex) { results.Add(new PSObject((object)ex.Message)); } runspace.Close(); StringBuilder stringBuilder = new StringBuilder(); foreach (PSObject obj in results) { stringBuilder.AppendLine(obj.ToString()); } return stringBuilder.ToString(); }
WinForm端调用说明
- 调用时必须搭配
async/await语法,不要使用Wait()或.Result,避免UI线程死锁 - await执行完成后会自动切回WinForm UI线程,可直接对窗体控件赋值,无需额外处理跨线程访问问题
调用示例:
// 按钮点击事件处理方法 private async void btnRunScript_Click(object sender, EventArgs e) { btnRunScript.Enabled = false; txtOutput.Text = "脚本执行中,请稍候..."; try { string execResult = await NewPsSessionAsync(txtServer.Text, txtScript.Text); txtOutput.Text = execResult; } catch (Exception ex) { txtOutput.Text = $"执行出错:{ex.Message}"; } finally { btnRunScript.Enabled = true; } }
核心改动点
- 方法返回值从
string修改为Task<string>,方法名新增Async后缀符合.NET异步命名规范 - 替换同步
Invoke()调用为异步实现,不会阻塞调用线程 - 新增using关键字自动释放Runspace和PowerShell对象,避免资源泄漏
内容的提问来源于stack exchange,提问作者Cosmin S
相关产品推荐
相关产品推荐

