从 C# 以编程方式调用 CmdLet 时,如何捕获 Powershell CmdLet 的详细输出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1146575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to capture a Powershell CmdLet's verbose output when the CmdLet is programmatically Invoked from C#
提问by namenlos
BACKGROUND
背景
- I am using Powershell 2.0 on Windows 7.
- I am writing a cmdlet in a Powershell module ("module" is new to Powershell 2.0).
- To test the cmdlet I am writing Unit tests in Visual Studio 2008 that programmatically invoke the cmdlet.
- 我在 Windows 7 上使用 Powershell 2.0。
- 我正在 Powershell 模块中编写一个 cmdlet(“模块”是 Powershell 2.0 的新功能)。
- 为了测试 cmdlet,我正在 Visual Studio 2008 中编写单元测试,以编程方式调用 cmdlet。
REFERENCE
参考
- This Article on MSDNcalled "How to Invoke a Cmdlet from Within a Cmdlet" shows how to call a cmdlet from C#.
- MSDN 上的这篇名为“如何从 Cmdlet 中调用 Cmdlet”的文章展示了如何从 C# 调用 cmdlet。
THE SOURCE CODE
源代码
This is a distilled version of my actual code — I've made it as small as possible so that you can see the problem I am having clearly:
using System; using System.Management.Automation; namespace DemoCmdLet1 { class Program { static void Main(string[] args) { var cmd = new GetColorsCommand(); foreach ( var i in cmd.Invoke<string>()) { Console.WriteLine("- " + i ); } } } [Cmdlet("Get", "Colors")] public class GetColorsCommand : Cmdlet { protected override void ProcessRecord() { this.WriteObject("Hello"); this.WriteVerbose("World"); } } }
这是我实际代码的提炼版本——我已经把它做得尽可能小,这样你就可以清楚地看到我遇到的问题:
using System; using System.Management.Automation; namespace DemoCmdLet1 { class Program { static void Main(string[] args) { var cmd = new GetColorsCommand(); foreach ( var i in cmd.Invoke<string>()) { Console.WriteLine("- " + i ); } } } [Cmdlet("Get", "Colors")] public class GetColorsCommand : Cmdlet { protected override void ProcessRecord() { this.WriteObject("Hello"); this.WriteVerbose("World"); } } }
COMMENTS
注释
- I understand how to enable and capture verbose output from the Powershell command line; that's not the problem.
- In this case I am programmatically invoking the cmdlet from C#.
- Nothing I've found addresses my specific scenario. Some articles suggest I should implement my own PSHost, but seems expensive and also it seems like a have to call the cmdlet as text, which I would like to avoid because that is not as strongly typed.
- 我了解如何从 Powershell 命令行启用和捕获详细输出;那不是问题。
- 在这种情况下,我以编程方式从 C# 调用 cmdlet。
- 我发现的任何内容都不能解决我的具体情况。一些文章建议我应该实现我自己的 PSHost,但看起来很昂贵,而且似乎必须将 cmdlet 作为文本调用,我想避免这种情况,因为它不是强类型的。
UPDATE ON 2009-07-20
2009-07-20 更新
Here is is the source code based on the answer below.
这是基于以下答案的源代码。
Some things are still not clear to me: * How to call the "Get-Colors" cmdlet (ideally without having to pass it as a string to the ps objet) * How to get the verbose output as it is generatedinstead of getting an collection of them at the end.
有些事情我仍然不清楚: * 如何调用“Get-Colors”cmdlet(理想情况下不必将其作为字符串传递给 ps objet) * 如何在生成时获取详细输出而不是获取最后收集它们。
using System;
using System.Management.Automation;
namespace DemoCmdLet1
{
class Program
{
static void Main(string[] args)
{
var ps = System.Management.Automation.PowerShell.Create();
ps.Commands.AddScript("$verbosepreference='continue'; write-verbose 42");
foreach ( var i in ps.Invoke<string>())
{
Console.WriteLine("normal output: {0}" , i );
}
foreach (var i in ps.Streams.Verbose)
{
Console.WriteLine("verbose output: {0}" , i);
}
}
}
[Cmdlet("Get", "Colors")]
public class GetColorsCommand : Cmdlet
{
protected override void ProcessRecord()
{
this.WriteObject("Red");
this.WriteVerbose("r");
this.WriteObject("Green");
this.WriteVerbose("g");
this.WriteObject("Blue");
this.WriteVerbose("b");
}
}
}
The code above generates this output:
上面的代码生成此输出:
d:\DemoCmdLet1\DemoCmdLet1>bin\Debug\DemoCmdLet1.exe
verbose output: 42
UPDATE ON 2010-01-16
2010-01-16 更新
by using the Powershell class (found in System.Management.Automation but only in the version of the assembly that comes with the powershell 2.0 SDK, not what comes out-of-the-box on Windows 7) I can programmatically call the cmdlet and get the verbose output. The remaining part is to actually add a custom cmdlet to that powershell instance - because that was my original goal - to unit test my cmdlets not those that come with powershell.
通过使用 Powershell 类(在 System.Management.Automation 中找到,但仅在 powershell 2.0 SDK 附带的程序集版本中,而不是在 Windows 7 上开箱即用的)我可以以编程方式调用 cmdlet 和获取详细输出。剩下的部分是实际向该 powershell 实例添加自定义 cmdlet - 因为这是我的最初目标 - 对我的 cmdlet 进行单元测试,而不是那些与 powershell 一起使用的 cmdlet。
class Program
{
static void Main(string[] args)
{
var ps = System.Management.Automation.PowerShell.Create();
ps.AddCommand("Get-Process");
ps.AddParameter("Verbose");
ps.Streams.Verbose.DataAdded += Verbose_DataAdded;
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine(
"output: {0,-24}{1}",
result.Members["ProcessName"].Value,
result.Members["Id"].Value);
}
Console.ReadKey();
}
static void Verbose_DataAdded(object sender, DataAddedEventArgs e)
{
Console.WriteLine( "verbose output: {0}", e.Index);
}
}
[Cmdlet("Get", "Colors")]
public class GetColorsCommand : Cmdlet
{
protected override void ProcessRecord()
{
this.WriteObject("Hello");
this.WriteVerbose("World");
}
}
回答by x0n
- Verbose output is not actually output unless
$VerbosePreference
is set at least to "Continue." - Use the PowerShell type to run your
cmdlet
, and readVerboseRecord
instances from theStreams.Verbose
propery
- 除非
$VerbosePreference
至少设置为“继续”,否则详细输出实际上并不是输出。 - 使用 PowerShell 类型运行您的
cmdlet
,并VerboseRecord
从Streams.Verbose
属性中读取实例
Example in powershell script:
PowerShell 脚本中的示例:
ps> $ps = [powershell]::create()
ps> $ps.Commands.AddScript("`$verbosepreference='continue'; write-verbose 42")
ps> $ps.invoke()
ps> $ps.streams.verbose
Message InvocationInfo PipelineIterationInfo
------- -------------- ---------------------
42 System.Management.Automation.Invocat... {0, 0}
This should be easy to translate into C#.
这应该很容易转换为 C#。
回答by Varun
1. string scriptFile = "Test.ps1";
2. using (PowerShell ps = PowerShell.Create())
3. {
4. const string getverbose = "$verbosepreference='continue'";
5. ps.AddScript(string.Format(getverbose));
6. ps.Invoke();
7. ps.Commands.Clear();
8. ps.AddScript(@".\" + scriptFile);
9. ps.Invoke();
10. foreach (var v in ps.Streams.Verbose)
11. {
12. Console.WriteLine(v.Message);
13. }
14. }
Important lines are line 5 and 6. This basically set the $verbosepreference for the session and for upcoming new commands and scripts.
重要的行是第 5 行和第 6 行。这基本上为会话和即将到来的新命令和脚本设置了 $verbosepreference。