如何将C#中使用Microsoft.PowerShell.SDK的同步方法改造为可await调用的异步方法
简单示例方法异步改造方案
如果方法本身是纯同步逻辑,没有可异步的IO操作,只需要兼容await调用形式,改造如下:
public Task DoSomethingAsync() { string d = "doing something"; return Task.CompletedTask; }
调用时直接使用await DoSomethingAsync()即可。
实际业务逻辑异步改造方案
第一步:改造底层PowerShell执行方法
Microsoft.PowerShell.SDK原生提供异步执行方法InvokeAsync,搭配文件异步读取API实现全链路异步:
private async Task<Collection<PSObject>> ExecutePSScriptAsync(string scriptFilePath) { using var ps = PowerShell.Create(); // 异步读取脚本文件内容 var scriptContent = await File.ReadAllTextAsync(scriptFilePath); ps.AddScript(scriptContent); // 异步执行PowerShell脚本 var asyncResult = await ps.InvokeAsync(); // 保持原有返回类型兼容上层逻辑 return new Collection<PSObject>(asyncResult.ToList()); }
第二步:改造脚本遍历执行方法(串行执行版本)
适合脚本之间有执行顺序依赖的场景:
public async Task RunValidationScriptsAsync() { string scriptDirPath = @"D:\ValidationScripts"; string[] psScriptsPath = Directory.GetFiles(scriptDirPath); Dictionary<string, Collection<PSObject>> result = new Dictionary<string, Collection<PSObject>>(); foreach (string scriptPath in psScriptsPath) { var executeResult = await ExecutePSScriptAsync(scriptPath); result.Add(scriptPath, executeResult); } // 此处可添加result的后续处理逻辑 }
可选:并行执行版本
适合脚本之间无依赖、需要提升执行效率的场景:
public async Task RunValidationScriptsAsync() { string scriptDirPath = @"D:\ValidationScripts"; string[] psScriptsPath = Directory.GetFiles(scriptDirPath); // 批量启动所有脚本异步执行任务 var scriptTasks = psScriptsPath.Select(async path => { var result = await ExecutePSScriptAsync(path); return (Path: path, Result: result); }); // 等待所有脚本执行完成 var executedResults = await Task.WhenAll(scriptTasks); // 组装结果字典 Dictionary<string, Collection<PSObject>> result = executedResults.ToDictionary(k => k.Path, v => v.Result); // 此处可添加result的后续处理逻辑 }
注意事项
- 异步方法默认遵循行业命名规范添加
Async后缀,方便调用方识别 - 原有同步逻辑中对PowerShell错误流的处理逻辑可以完全复用,异步执行后依然可以通过
ps.HadErrors、ps.Streams.Error获取错误信息 - 调用时直接使用
await RunValidationScriptsAsync()即可满足需求
内容的提问来源于stack exchange,提问作者Dev
相关产品推荐
相关产品推荐

