Создание командлетов PowerShell в C # - конвейерная цепочка - PullRequest
5 голосов
/ 01 ноября 2019

У меня есть несколько классов в C #, которые я хотел бы использовать в конвейерах, я видел статьи об этом, но пока не смог этого сделать.

Вот как я их используюпрямо сейчас:

$suite = [MyProject.SuiteBuilder]::CreateSuite('my house')

$houseSet = $suite.AddSet('doors', 'These represents doors')
$houseSet.AddOption('blue', 'kitchen')
$houseSet.AddOption('black', 'bedreoom')
$houseSet.AddOption('white', 'toilet')

И я хочу иметь возможность использовать это с конвейерами:

$suite = [MyProject.SuiteBuilder]::CreateSuite('my house')

$suite | AddSet('doors', 'These represents doors') `
       | AddOption('blue', 'kitchen') `
       | AddOption('black', 'bedreoom') `
       | AddOption('white', 'toilet')

Вот мои классы C #:

//SuiteBuilder.cs
public static class SuiteBuilder
{
    public static Suite CreateTestSuite(string name)
    {
        return new Suite(name);
    }
}

//Suite.cs
public class Suite : PSCmdlet
{
    public string Name { get; set; }
    public IEnumerable<Set> Sets { get; set; }

    public Suite(string name)
    {
        Name = name;
        Sets = new List<Set>();
    }

    // call this method in pipeline
    public Set AddSet(string type, string description)
    {
        Sets.Add(new Set(type, description));
        return Sets.Last();
    }
}


//Set.cs
public class Set : PSCmdlet
{
    public string Type { get; set; }
    public string Description { get; set; }
    public IEnumerable<Option> Options { get; set; }

    public Set(string type, string description)
    {
        Type = type;
        Description = description;
        Options = new List<Option>();
    }

    // call this method from pipeline
    public Set AddOption(string color, string place)
    {
        Options.Add(new Option(color, place));
        return this;
    }
}


//option.cs
public class Option : PSCmdlet
{
    public string Color { get; set; }
    public string Place { get; set; }

    public Option(string color, string place)
    {
        Color = color;
        Place = place;
    }
}

И я изо всех сил пытаюсь сделать эти функции доступными для вызова в конвейерной форме.

Я также добавил комментарий, например call this method in pipeline, перед каждым комментарием, который мне нужно вызвать.

Ответы [ 2 ]

2 голосов
/ 09 ноября 2019

Короче говоря, вам необходимо:

  • Принять параметр из конвейера с помощью [Parameter(ValueFromPipeline =true)]
  • Предоставить вывод в конвейер, вызвав метод WriteObject в методе процесса

Подробный пошаговый ответ

В этом посте я немного реорганизую ваш код и покажу, как вы можете создать Командлет Powershell в C # и как определяют параметры , принимают параметры из конвейера и обеспечивают вывод в конвейер . Затем вы можете легко написать что-то вроде:

$suite = [MyCmdLets.Suite]::New("suite1")
$suite | Add-Set "type1" "desc1"`
       | Add-Option "color1" "place1"`
       | Add-Option "color2" "place2" | Out-Null

Для этого выполните следующие действия:

  1. Создайте проект библиотеки класса C # (например, назовите его MyCmdlets)
  2. Установочный пакет Microsoft.PowerShell.5.ReferenceAssemblies
  3. Создайте классы модели независимо от PowerShell. (См. Код внизу поста)
  4. Создайте командлеты с учетом следующих примечаний: (См. Код внизу поста)

    • Для каждого командлета,создать класс C #
    • Производный от Cmdlet class
    • Украсить класс атрибутом CmdletAttribute, указав глагол и имя после глаголаНапример, если вы хотите иметь Add-Set, используйте [Cmdlet(VerbsCommon.Add, "Set")].
    • Если вы хотите иметь вывод для конвейера, украсьте класс атрибутом OutputTypeAttribute, указав типвыходных данных, например, если вы хотите иметь вывод типа Set для конвейера, используйте [OutputType(typeof(Set))].
    • Для каждого входного параметра вашего командлета определите свойство C #.
    • Декорируйте каждое свойство параметра атрибутом Parameter.
    • Если вы хотите принять параметр из конвейера, при декорировании с атрибутом ParameterAttribute установите ValueFromPipeline в true, для примера [Parameter(ValueFromPipeline =true)
    • Чтобы обеспечить вывод в конвейер, переопределите конвейерметоды обработки, такие как ProcessRecord и использование WriteObject записывают в вывод.
  5. Сборка проекта.

  6. Откройте PowerShell ISE и запустите следующий код:

    Import-Module "PATH TO YOUR BIN DEBUG FOLDER\MyCmdlets.dll"
    
    $suite = [MyCmdLets.Suite]::New("suite1")
    $suite | Add-Set "type1" "desc1"`
           | Add-Option "color1" "place1"`
           | Add-Option "color2" "place2" | Out-Null
    

    Будет создана такая структура:

    Name   Sets           
    ----   ----           
    suite1 {MyCmdlets.Set}
    
    
    Type  Description Options                             
    ----  ----------- -------                             
    type1 desc1       {MyCmdlets.Option, MyCmdlets.Option}
    
    
    Color  Place 
    -----  ----- 
    color1 place1
    color2 place2
    

Пример кода

Классы моделей

Как уже упоминалось выше, создавайте классы вашей модели независимо от PowerShell следующим образом:

using System.Collections.Generic;
namespace MyCmdlets
{
    public class Suite
    {
        public string Name { get; set; }
        public List<Set> Sets { get; } = new List<Set>();
        public Suite(string name) {
            Name = name;
        }
    }
    public class Set
    {
        public string Type { get; set; }
        public string Description { get; set; }
        public List<Option> Options { get; } = new List<Option>();
        public Set(string type, string description) {
            Type = type;
            Description = description;
        }
    }
    public class Option 
    {
        public string Color { get; set; }
        public string Place { get; set; }
        public Option(string color, string place) {
            Color = color;
            Place = place;
        }
    }
}

CmdLet Classes

Также создайте классы командлетов на основе заметок, которые я описал выше:

using System.Management.Automation;
namespace MyCmdlets
{
    [Cmdlet(VerbsCommon.Add, "Set"), OutputType(typeof(Set))]
    public class AddSetCmdlet : Cmdlet
    {
        [Parameter(ValueFromPipeline = true, Mandatory = true)]
        public Suite Suite { get; set; }
        [Parameter(Position = 0, Mandatory = true)]
        public string Type { get; set; }
        [Parameter(Position = 1, Mandatory = true)]
        public string Description { get; set; }
        protected override void ProcessRecord() {
            var set = new Set(Type, Description);
            Suite.Sets.Add(set);
            WriteObject(set);
        }
    }

    [Cmdlet(VerbsCommon.Add, "Option"), OutputType(typeof(Option))]
    public class AddOptionCmdlet : Cmdlet
    {
        [Parameter(ValueFromPipeline = true, Mandatory = true)]
        public Set Set { get; set; }
        [Parameter(Position = 0, Mandatory = true)]
        public string Color { get; set; }
        [Parameter(Position = 1, Mandatory = true)]
        public string Place { get; set; }
        protected override void ProcessRecord() {
            var option = new Option(Color, Place);
            Set.Options.Add(option);
            WriteObject(Set);
        }
    }
}
0 голосов
/ 09 ноября 2019

Вы можете использовать ValueFromPipeline = $ true. Однако вам придется ссылаться на переменную типа и возвращать элемент, если вы хотите продолжить конвейер. Я не знаю, как обойти это. Поскольку он вернется, вам нужно будет добавить Out-Null в конце, чтобы он не попал в консоль.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_ref?view=powershell-6

function Add-Option {
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ref]$Item,
        [Parameter(Mandatory = $true, Position = 0)]
        [String]$Color
        [Parameter(Mandatory = $true, Position = 1)]
        [String]$Room
    )
    $Item.Value.AddOption($Color,$Room)
    return $Item
}

$suite = [MyProject.SuiteBuilder]::CreateSuite('my house')

[ref]$suite | Add-Option 'blue' 'kitchen' `
            | Add-Option 'black' 'bedroom' `
            | Out-Null

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...