【问题标题】:Get Powershell command's output when invoked through code通过代码调用时获取 Powershell 命令的输出
【发布时间】:2022-03-28 05:08:57
【问题描述】:

我编写了一段代码(用 C# 编写)来使用 System.Management.Automation 执行 Powershell 脚本(特别是 Azure PowerShell)。 powershell脚本基本上是在Azure上的一个容器中上传一个vhd,当通过azure Powershell手动输入命令时,它会显示上传进度和经过的时间等。通过代码一切正常,但我想在命令执行期间(即pipeline.invoke();)获取命令的结果/输出(即上传进度、经过的时间),这是代码:

 RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
 Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
 runspace.Open();
 RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
 Pipeline pipeline = runspace.CreatePipeline();

 Command myCommand = new Command(scriptPath);
 foreach (var argument in arguments)
 {
     myCommand.Parameters.Add(new CommandParameter(argument.Key, argument.Value));
 }
 pipeline.Commands.Add(myCommand);

 var results = pipeline.Invoke(); // i want to get results here (i.e. during command execution) 
 foreach (var psObject in results)
 {
     System.Diagnostics.Debug.Write(psObject.BaseObject.ToString());
 }

如果可以从 Powershell 检索实时输出,请指导。

【问题讨论】:

  • 使用PowerShell 类而不是Pipeline。然后异步调用并读取PowerShell.Streams.Progress
  • 你能指导更多使用一些代码吗?
  • 我已经添加了答案
  • 感谢我试一试..
  • 明确地说,有了DataAdded 事件处理程序,您不需要异步调用它。 Invoke() 会很好

标签: c# powershell azure


【解决方案1】:

除非您以 PowerShell 1.0 为目标,否则无需手动设置运行空间和管道,而是创建 PowerShell class 的实例:

PowerShell psinstance = PowerShell.Create();
psinstance.AddScript(scriptPath);
var results = psinstance.Invoke();

更简单。


现在,PowerShell 类通过Streams property 公开各种非标准输出流(详细、调试、错误等) - 包括进度流,因此您可以订阅它,如下所示:

psinstance.Streams.Progress.DataAdded += myProgressEventHandler;

然后在您的事件处理程序中:

static void myProgressEventHandler(object sender, DataAddedEventArgs e)
{
    ProgressRecord newRecord = ((PSDataCollection<ProgressRecord>)sender)[e.Index];
    if (newRecord.PercentComplete != -1)
    {
        Console.Clear();
        Console.WriteLine("Progress updated: {0}", newRecord.PercentComplete);
    }
}

作为一个例子,下面是上面显示的事件处理程序,同时在一个简单的控制台应用程序中运行一个编写进度信息的示例脚本(下面发布的示例脚本):

Test-Progress.ps1

function Test-Progress
{
    param()

    Write-Progress -Activity 'Testing progress' -Status 'Starting' -PercentComplete 0
    Start-Sleep -Milliseconds 600
    1..10 |ForEach-Object{
        Write-Progress -Activity "Testing progress" -Status 'Progressing' -PercentComplete $(5 + 6.87 * $_)
        Start-Sleep -Milliseconds 400
    }
    Write-Progress -Activity 'Testing progress' -Status 'Ending' -PercentComplete 99
    Start-Sleep -Seconds 2
    Write-Progress -Activity 'Testing progress' -Status 'Done' -Completed
}

Test-Progress

【讨论】:

  • 您好,我正在使用 PowerShell 类,但从未为我触发 DataAdded 事件。我的问题是为什么?我的代码如下所示: using (PowerShell powerShell = PowerShell.Create()) { powerShell.AddScript(scriptText); powerShell.Streams.Progress.DataAdded += ProgressDataAdded;集合 PSOutput = powerShell.Invoke(); }
  • @IonutEnache 请ask a new question 并包含处理程序代码以及您迄今为止尝试过的内容:)
【解决方案2】:

可能有点晚了,但仍然。

@Mathias R. Jessen 的回答效果很好,但对于输出普通字符串的情况(没有 Write-Progress 等):

先初始化集合

PSDataCollection<PSObject> output = new PSDataCollection<PSObject>();
output.DataAdded += Output_DataAdded;

表演

var res = psinstance.BeginInvoke<PSObject, PSObject>(null, output);
res.AsyncWaitHandle.WaitOne();

实时获取结果

private static void Output_DataAdded(object sender, DataAddedEventArgs e)
{
    PSObject newRecord = ((PSDataCollection<PSObject>)sender)[e.Index];
    Console.WriteLine(newRecord);
}

Get-Process PS 命令上测试。

【讨论】:

    猜你喜欢
    • 2014-04-23
    • 2021-12-04
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 2023-03-27
    相关资源
    最近更新 更多