ЗАДНИЙ ПЛАН
- Я использую Powershell 2.0 в Windows 7.
- Я пишу командлет в модуле Powershell («модуль» впервые появился в Powershell 2.0).
- Чтобы протестировать командлет, я пишу модульные тесты в Visual Studio 2008, которые программно вызывают командлет.
ССЫЛКА
- В этой статье на MSDN под названием «Как вызвать командлет из командлета» показано, как вызвать командлет из C #.
ИСХОДНЫЙ КОД
Это дистиллированная версия моего фактического кода, который я сделал как можно меньше, чтобы вы могли ясно увидеть проблему, с которой я столкнулся:
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"); } } }
КОММЕНТАРИИ
- Я понимаю, как включить и записать подробный вывод из командной строки Powershell; это не проблема.
- В этом случае я программно вызываю командлет из C #.
- Ничего из того, что я нашел, не соответствует моему конкретному сценарию. В некоторых статьях предлагается реализовать собственный PSHost, но это кажется дорогостоящим, а также кажется, что командлет нужно вызывать как текст, чего я бы хотел избежать, потому что он не так строго типизирован.
ОБНОВЛЕНИЕ 2009-07-20
Вот исходный код, основанный на ответе ниже.
Некоторые вещи мне до сих пор не ясны: * Как вызвать командлет "Get-Colors" (в идеале без необходимости передавать его в виде строки в объект ps) * Как получить подробный вывод по мере его создания < / em> вместо того, чтобы получить их коллекцию в конце.
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");
}
}
}
Приведенный выше код генерирует такой вывод:
d:\DemoCmdLet1\DemoCmdLet1>bin\Debug\DemoCmdLet1.exe
verbose output: 42
ОБНОВЛЕНИЕ 16 января 2010 г.
с помощью класса Powershell (который находится в System.Management.Automation, но только в той версии сборки, которая поставляется с SDK powershell 2.0, а не в Windows 7), я могу программно вызвать командлет и получить подробный вывод. Оставшаяся часть - это фактически добавить настраиваемый командлет к этому экземпляру PowerShell - потому что это было моей первоначальной целью - провести модульное тестирование моих командлетов, а не тех, которые поставляются с PowerShell.
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");
}
}