订阅 c# 中的 powershell 进度不起作用
Subscribing to powershell progress in c# not working
我正在编写一个 C# GUI 程序,它使用 System.Management.Automation 在运行时创建的实例上执行 powershell 命令,我需要它是一个持久的 powershell 实例,以便我可以发送多个命令并收集输出在运行时。这按预期工作,但我在订阅进度事件时遇到了一些问题。它仅在我输入错误命令并写入进度为 -1% 时触发。
当我输入正确的命令时,它根本不触发。
错误和输出事件正常工作,所以我不确定出了什么问题。
我发现另外两个人也有类似的问题,但他们的解决方案对我不起作用,我在下面链接了他们。这是我到目前为止未成功使用的代码。
public class CodeHandler {
public static PowerShell psInstance;
public void init() {
//Create powershell instance
psInstance = PowerShell.Create();
}
public async Task < string > ExecutePowershellCommand(string script) {
psInstance.AddScript(script);
psInstance.AddCommand("Out-String");
PSDataCollection < PSObject > outputCollection = new PSDataCollection < PSObject > ();
outputCollection.DataAdded += outputCollection_DataAdded;
//The Part I Can't Get To Work
psInstance.Streams.Progress.DataAdded += (sender, eventargs) => {
PSDataCollection < ProgressRecord > progressRecords = (PSDataCollection < ProgressRecord > ) sender;
Console.WriteLine("!Progress is {0} percent complete", progressRecords[eventargs.Index].PercentComplete);
};
psInstance.Streams.Error.DataAdded += Error_DataAdded;
IAsyncResult result = psInstance.BeginInvoke < PSObject, PSObject > (null, outputCollection);
while (!result.IsCompleted) {
Console.WriteLine("Waiting for pipeline to finish...");
await Task.Delay(100);
}
PSInvocationState state = psInstance.InvocationStateInfo.State;
Console.WriteLine("Execution has stopped. The pipeline state: " + state);
if (state != PSInvocationState.Completed)
return string.Empty;
StringBuilder stringBuilder = new StringBuilder();
foreach(PSObject outputItem in outputCollection) {
stringBuilder.AppendLine(outputItem.BaseObject.ToString());
Console.WriteLine(outputItem.BaseObject.ToString());
}
return stringBuilder.ToString();
}
}
参考文献:
添加psInstance.EndInvoke(result);
如下图:
...
IAsyncResult result = psInstance.BeginInvoke < PSObject, PSObject > (null, outputCollection);
while (!result.IsCompleted) {
Console.WriteLine("Waiting for pipeline to finish...");
await Task.Delay(100);
}
psInstance.EndInvoke(result);
...
您的脚本需要使用 Write-Progress
示例脚本
# Use Get-Command to get list of commands and store them in the $cmds variable.
$cmds = Get-Command
# Pipe the events to the ForEach-Object cmdlet.
$cmds | ForEach-Object -Begin {
# In the Begin block, use Clear-Host to clear the screen.
Clear-Host
# Set the $i counter variable to zero.
$i = 0
# Set the $out variable to a empty string.
$out = ""
} -Process {
# get name
# Append to the out variable.
# $out=$out + $_
write-output ($_.Name + " " + $_.Version)
# Increment the $i counter variable which is used to create the progress bar.
$i = $i+1
# Use Write-Progress to output a progress bar.
# The Activity and Status parameters create the first and second lines of the progress bar heading, respectively.
Write-Progress -Activity "Searching Commands" -Status "Progress:" -PercentComplete ($i/$cmds.count*100)
} -End {
# Display using the out variable.
# $out
}
我正在编写一个 C# GUI 程序,它使用 System.Management.Automation 在运行时创建的实例上执行 powershell 命令,我需要它是一个持久的 powershell 实例,以便我可以发送多个命令并收集输出在运行时。这按预期工作,但我在订阅进度事件时遇到了一些问题。它仅在我输入错误命令并写入进度为 -1% 时触发。
当我输入正确的命令时,它根本不触发。 错误和输出事件正常工作,所以我不确定出了什么问题。
我发现另外两个人也有类似的问题,但他们的解决方案对我不起作用,我在下面链接了他们。这是我到目前为止未成功使用的代码。
public class CodeHandler {
public static PowerShell psInstance;
public void init() {
//Create powershell instance
psInstance = PowerShell.Create();
}
public async Task < string > ExecutePowershellCommand(string script) {
psInstance.AddScript(script);
psInstance.AddCommand("Out-String");
PSDataCollection < PSObject > outputCollection = new PSDataCollection < PSObject > ();
outputCollection.DataAdded += outputCollection_DataAdded;
//The Part I Can't Get To Work
psInstance.Streams.Progress.DataAdded += (sender, eventargs) => {
PSDataCollection < ProgressRecord > progressRecords = (PSDataCollection < ProgressRecord > ) sender;
Console.WriteLine("!Progress is {0} percent complete", progressRecords[eventargs.Index].PercentComplete);
};
psInstance.Streams.Error.DataAdded += Error_DataAdded;
IAsyncResult result = psInstance.BeginInvoke < PSObject, PSObject > (null, outputCollection);
while (!result.IsCompleted) {
Console.WriteLine("Waiting for pipeline to finish...");
await Task.Delay(100);
}
PSInvocationState state = psInstance.InvocationStateInfo.State;
Console.WriteLine("Execution has stopped. The pipeline state: " + state);
if (state != PSInvocationState.Completed)
return string.Empty;
StringBuilder stringBuilder = new StringBuilder();
foreach(PSObject outputItem in outputCollection) {
stringBuilder.AppendLine(outputItem.BaseObject.ToString());
Console.WriteLine(outputItem.BaseObject.ToString());
}
return stringBuilder.ToString();
}
}
参考文献:
添加psInstance.EndInvoke(result);
如下图:
...
IAsyncResult result = psInstance.BeginInvoke < PSObject, PSObject > (null, outputCollection);
while (!result.IsCompleted) {
Console.WriteLine("Waiting for pipeline to finish...");
await Task.Delay(100);
}
psInstance.EndInvoke(result);
...
您的脚本需要使用 Write-Progress
示例脚本
# Use Get-Command to get list of commands and store them in the $cmds variable.
$cmds = Get-Command
# Pipe the events to the ForEach-Object cmdlet.
$cmds | ForEach-Object -Begin {
# In the Begin block, use Clear-Host to clear the screen.
Clear-Host
# Set the $i counter variable to zero.
$i = 0
# Set the $out variable to a empty string.
$out = ""
} -Process {
# get name
# Append to the out variable.
# $out=$out + $_
write-output ($_.Name + " " + $_.Version)
# Increment the $i counter variable which is used to create the progress bar.
$i = $i+1
# Use Write-Progress to output a progress bar.
# The Activity and Status parameters create the first and second lines of the progress bar heading, respectively.
Write-Progress -Activity "Searching Commands" -Status "Progress:" -PercentComplete ($i/$cmds.count*100)
} -End {
# Display using the out variable.
# $out
}