How can I preview the PowerShell command before execute?

Viewed 388

Let's say I have the following PowerShell source:

PowerShell shell = PowerShell.Create().AddCommand("Get-NetAdapter")
                                      .AddParameter("name", "Ethernet*")
                                      .AddParameter("ThrottleLimit", 5);

Now, before call shell.Invoke(), I want check, for logging purposes, the final command line. In this case I expect something like

Get-NetAdapter -name Ethernet* -ThrottleLimit 5

I tested these, but none works:

shell.Commands.ToString()
shell.Commands.Commands.ToString()
shell.Commands.Commands.First().CommandText
shell.Commands.Commands.First().ToString()

Is there some built in way to check the final command line?

2 Answers

How about:

namespace SomeProject.Extensions
{
    using System;
    using System.Management.Automation;
    using System.Management.Automation.Runspaces;
    using System.Text;

    public static class PowerShellExtensions
    {
        public static void LogCommandLine(this PowerShell commandToLog)
        {
            foreach (Command command in commandToLog.Commands.Commands)
            {
                StringBuilder commandLine = new StringBuilder(command.ToString());

                foreach (CommandParameter parameter in command.Parameters)
                {
                    commandLine.Append($" --{parameter.Name} {parameter.Value}");
                }

                Console.WriteLine(commandLine.ToString());
            }
        }
    }
}

which given

namespace SomeProject.Extensions.UnitTests
{
    using System.Management.Automation;
    using NUnit.Framework;

    [TestFixture]
    [Parallelizable(ParallelScope.All)]
    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
    public class PowerShellExtensionsTests
    {
        [Test]
        [Category(nameof(PowerShellExtensions))]
        public void TestCommandLine()
        {
            PowerShell shell = PowerShell.Create().AddCommand("Get-NetAdapter")
                                                  .AddParameter("name", "Ethernet*")
                                                  .AddParameter("ThrottleLimit", 5);

            shell.LogCommandLine();
        }
    }
}

Outputs what you wanted:

Get-NetAdapter --name Ethernet* --ThrottleLimit 5

Given more complex parameters, you may need to get more fancy as it will just output the type of the parameter and not necessarily a nice string representation of it.

If you specifically need to log the creation of the object as you are constructing it from parameters, you may want to consider creating an extension method that logs the parameters during construction.

class Program
    {
        static void Main()
        {
            PowerShell shell = PowerShell.Create().Setup("Get-NetAdapter", ("name", "Ethernet"), ("ThrottleLimit", 5));
        }
    }
    public static class Logger
    {
        public static void Log(in string message)
        {
            Console.WriteLine(message);
        }
    }
    public static class PowershellExtenstions
    {
        public static PowerShell Setup(this PowerShell powerShell, in string command, params (string Name, object Value)[] parameters)
        {
            string message = command ?? string.Empty;

            powerShell.AddCommand(command);

            foreach (var parameter in parameters)
            {
                message += $" -{ parameter.Name } { parameter.Value }";

                powerShell.AddParameter(parameter.Name, parameter.Value);
            }

            Logger.Log(message);

            return powerShell;
        }
    }
Related