2

How would I use the code used to create powershell cmdlets in another c# method instead of a powershell script.

I have the following code:

public class Program
{
    static void Main(string[] args)
    {
        var getCommand = new GetCommand { Text = "Hello World"};

        //help needed here
    }
}

[Cmdlet("Test", "Get")]
public class GetCommand : Cmdlet
{
    [Parameter(Mandatory = true)]
    public string Text { get; set; }

    protected override void ProcessRecord()
    {
        WriteObject(Text);
    }
}

2 Answers2

2

Don't instantiate the GetCommand class - PowerShell will do that for you!

First, you'll need to spin up an instance of the PowerShell class to execute your command:

PowerShell ps = PowerShell.Create();

Then add a CommandInfo reference with the AddCommand method:

ps.AddCommand(new CmdletInfo("Test-Get", typeof(GetCommand)));

And then add your parameter argument:

ps.AddParameter("Text", "Hello World");

Now you can execute it (and collect the output) with the Invoke() method:

var output = ps.Invoke();
foreach(var obj in ouput)
{
    Console.WriteLine("Output was: {0}", obj);
}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
1

Extract the logic in a seperate class and call it directly. Use the cmdlet to be, well, just a shell around this new class. This Seperation of Concerns (SoC) also enables easier unit tests and leads to an overall cleaner architecture.

Extracted Class Greeter.cs

public class Greeter {
    public Greeter(string name) {
        _Name = name;
    }
    private string _Name;
    public string SayHello() {
        return $"Hello {_Name}";
    }
    public string SayGoodBye() {
        return $"So long {_Name}, and thanks for all the fish!";
    }
}

CommandLet GetGreetingCommand.cs

[Cmdlet("Greeting", "Get")]
public class GetGreetingCommand : Cmdlet {
    [Parameter(Mandatory = true)]
    public string Name { get; set; }

    protected override void ProcessRecord() {
        var greeter = new Greeter(Name);
        var greeting = greeter.SayHello();
        WriteObject(greeting);
    }
}

CommandLet GetGoodByeCommand .cs

[Cmdlet("GoodBye", "Get")]
public class GetGoodByeCommand : Cmdlet {
    [Parameter(Mandatory = true)]
    public string Name { get; set; }

    protected override void ProcessRecord() {
        var greeter = new Greeter(Name);
        var goodBye = greeter.SayGoodBye();
        WriteObject(goodBye);
    }
}

Console Main.cs (or any other client-code of Greeter-class)

public static void main(string[] args) {
    var greeter = new Greeter(args.FirstOrDefault());
    Console.WriteLine(greeter.SayHello());
    Console.WriteLine(greeter.SayGoodBye());
}

TestCase

public static void SayingHelloUsesName() {
    var sut = new Greeter("Arthur");

    var expected = "Hello Arthur";
    var actual = sut.SayHello();

    Assert.AreEqual(expected, actual);
}

The two concerns here are - the actual BusinessLogic (Greeter.cs) - interoperability with PowerShell, providing mechanisms to parameterize the cmdlet, etc. (Get*Command.cs). As you see, the cmdlets really only pass through the calls, while enabling use via PowerShell.

@Mathias R. Jessen ´ answer could be usefull, if you need to call third party cmdlets, but in most cases, there should be an appropriate (non-powershell) API for what you are trying to do.

earloc
  • 2,070
  • 12
  • 20
  • Can you provide an example? – Bhavik Ramsundar Apr 25 '17 at 05:26
  • there you go ;) – earloc Apr 25 '17 at 08:20
  • 1
    @earloc While this is arguably better separated code, you're not really addressing the question "how do I run my PowerShell cmdlet in C#"? – Mathias R. Jessen Apr 25 '17 at 10:21
  • Our answers both provide adequate strategies to deal with this kind of problem, so the questioner gets more options to choose from. And isn't it that, what this platform is all about? I prefer answering questions with a bit of broader sight (does this translate? ;) ), in hope of overall better software (developers). – earloc Apr 25 '17 at 10:58
  • @earloc I agree with your interpretation of the point of the stackoverflow exercise, but there are competing agendae. What the users want, what the badge collectors and OCD indulgers want, and what the for-profit company wants are only loosely aligned. Every year they ask me what I think and then get nasty with downvoting when I dare to hold an opinion they don't like. I've stopped voting, it's obvious they don't want to know about dissenting opinions. – Peter Wone Jul 13 '20 at 02:56