如何在 C# 中跟踪 Powershell 进度和错误?
How do I track a Powershell progress and errors in C#?
我目前正在编写一个 WPF 应用程序,它允许用户将
.vmdk (VMware vm file)
到
.vhdx (Hyper-V vm file).
我正在使用一个 cmdlet (ConvertTo-MvmcVirtualHardDisk),它驻留在 MvmcCmdlet.psd1 模块中,
Microsoft Virtual Machine Converter 3.0.0
我正在使用硬编码路径 atm 测试功能。
这是我当前的代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Threading;
using System.Windows;
namespace PowershellTestArea
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string output { get; set; }
public MainWindow()
{
InitializeComponent();
}
private void Button_OnClick(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
Runspace rs = RunspaceFactory.CreateRunspace();
rs.ThreadOptions = PSThreadOptions.UseCurrentThread;
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Import-Module", true).AddParameter("Name", @"C:\Program Files\Microsoft Virtual Machine Converter\MvmcCmdlet.psd1");
ps.Invoke();
Debug.WriteLine(ps.HadErrors);
Thread.Sleep(3000);
ps.AddCommand("ConvertTo-MvmcVirtualHardDisk")
.AddParameter("–SourceLiteralPath", @"'C:\VM\Windows 7 x64.vmdk'")
.AddParameter("-VhdFormat", "Vhdx");
Debug.WriteLine(ps.HadErrors);
ps.BeginInvoke();
IAsyncResult asyncResult = ps.BeginInvoke<PSObject, PSObject>(null, output);
while (!asyncResult.IsCompleted)
{
Debug.WriteLine("Running...");
}
Debug.WriteLine(ps.Streams.Error.ToString());
rs.Close();
}).Start();
}
}
}
我在 新线程 中执行 Powershell 代码的原因是,该模块已导入并且可以在 运行 时使用。我想确保它是在同一个会话中导入的,可以这么说。
过程:
ps.AddCommand("ConvertTo-MvmcVirtualHardDisk")
.AddParameter("–SourceLiteralPath", @"'C:\VM\Windows 7 x64.vmdk'")
.AddParameter("-VhdFormat", "Vhdx");
Debug.WriteLine(ps.HadErrors);
ps.BeginInvoke();
完成得非常快(HadErrors returns false),当 运行 在 powershell 中时,大约需要 40 分钟才能完成。
任何人都可以告诉我该怎么做,跟踪进度,以便转换可以 done/finish?
编辑:
与的区别是我的进程没有正确完成,我想知道如何给进程时间来完成。
Powershell 中的进度是一个流,就像错误、警告、调试等。所有流都可以通过 PSDataStreams class, exposed through the Powershell.Streams 属性.
您可以通过订阅 DataAdded
事件来监听 Progress 流上的 Progress 事件,例如:
ps.Streams.Progress.DataAdded += (sender,args) => {
var records = (PSDataCollection<ProgressRecord>)sender;
var current=records[args.Index];
Console.WriteLine("VM conversion is {0} percent complete", current.PercentComplete);
};
您可以用类似的方式收听其余的流,例如 Errors stream is a collection of ErrorRecord 对象。您可以用同样的方式收听信息、Verbose、Warning 消息,以构建所发生事件的完整日志。
另一种选择是创建一个 Transcript Powershell 会话。这会将会话的所有命令和输出保存到文本文件中,从调用 Start-Transcript 到调用 Stop-Transcript,例如:
Start-Transcript -OutputDirectory 'c:\mylogs' -noclobber -IncludeInvocationHeader
ConvertTo-MvmcVirtualHardDisk ...
Stop-Transcript
或使用 C# 的等效代码。
这是一种捕获所有内容以进行故障排除的快速而简单的方法
我目前正在编写一个 WPF 应用程序,它允许用户将
.vmdk (VMware vm file)
到
.vhdx (Hyper-V vm file).
我正在使用一个 cmdlet (ConvertTo-MvmcVirtualHardDisk),它驻留在 MvmcCmdlet.psd1 模块中,
Microsoft Virtual Machine Converter 3.0.0
我正在使用硬编码路径 atm 测试功能。
这是我当前的代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Threading;
using System.Windows;
namespace PowershellTestArea
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string output { get; set; }
public MainWindow()
{
InitializeComponent();
}
private void Button_OnClick(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
Runspace rs = RunspaceFactory.CreateRunspace();
rs.ThreadOptions = PSThreadOptions.UseCurrentThread;
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Import-Module", true).AddParameter("Name", @"C:\Program Files\Microsoft Virtual Machine Converter\MvmcCmdlet.psd1");
ps.Invoke();
Debug.WriteLine(ps.HadErrors);
Thread.Sleep(3000);
ps.AddCommand("ConvertTo-MvmcVirtualHardDisk")
.AddParameter("–SourceLiteralPath", @"'C:\VM\Windows 7 x64.vmdk'")
.AddParameter("-VhdFormat", "Vhdx");
Debug.WriteLine(ps.HadErrors);
ps.BeginInvoke();
IAsyncResult asyncResult = ps.BeginInvoke<PSObject, PSObject>(null, output);
while (!asyncResult.IsCompleted)
{
Debug.WriteLine("Running...");
}
Debug.WriteLine(ps.Streams.Error.ToString());
rs.Close();
}).Start();
}
}
}
我在 新线程 中执行 Powershell 代码的原因是,该模块已导入并且可以在 运行 时使用。我想确保它是在同一个会话中导入的,可以这么说。 过程:
ps.AddCommand("ConvertTo-MvmcVirtualHardDisk")
.AddParameter("–SourceLiteralPath", @"'C:\VM\Windows 7 x64.vmdk'")
.AddParameter("-VhdFormat", "Vhdx");
Debug.WriteLine(ps.HadErrors);
ps.BeginInvoke();
完成得非常快(HadErrors returns false),当 运行 在 powershell 中时,大约需要 40 分钟才能完成。
任何人都可以告诉我该怎么做,跟踪进度,以便转换可以 done/finish?
编辑:
与
Powershell 中的进度是一个流,就像错误、警告、调试等。所有流都可以通过 PSDataStreams class, exposed through the Powershell.Streams 属性.
您可以通过订阅 DataAdded
事件来监听 Progress 流上的 Progress 事件,例如:
ps.Streams.Progress.DataAdded += (sender,args) => {
var records = (PSDataCollection<ProgressRecord>)sender;
var current=records[args.Index];
Console.WriteLine("VM conversion is {0} percent complete", current.PercentComplete);
};
您可以用类似的方式收听其余的流,例如 Errors stream is a collection of ErrorRecord 对象。您可以用同样的方式收听信息、Verbose、Warning 消息,以构建所发生事件的完整日志。
另一种选择是创建一个 Transcript Powershell 会话。这会将会话的所有命令和输出保存到文本文件中,从调用 Start-Transcript 到调用 Stop-Transcript,例如:
Start-Transcript -OutputDirectory 'c:\mylogs' -noclobber -IncludeInvocationHeader
ConvertTo-MvmcVirtualHardDisk ...
Stop-Transcript
或使用 C# 的等效代码。
这是一种捕获所有内容以进行故障排除的快速而简单的方法