0

I am trying to run a powershell script in c# that contains among other the command: Get-Credential

I can run the file with the Process Command:

 public static void RunFile(string ps1File)
        {
            
            var startInfo = new ProcessStartInfo()
            {
                FileName = "powershell.exe",
                Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{ps1File}\"",
                UseShellExecute = false,
                CreateNoWindow = true
            };
            try
            {
                Process P = Process.Start(startInfo);
                P.WaitForExit();
                var result = P.ExitCode;
                System.Diagnostics.Debug.WriteLine("Error: " + result);
            }
            catch (Exception e)
            {
                throw;
            }
        }

but with that I dont get the PS return value. So I am trying the System.Management.Automation but now I have the issue that the PS windows does not come up and I get straight my error code:

public async static void RunFileTest(string ps1File) {

    PowerShell ps = PowerShell.Create();

    //PowerShell ps = PowerShell.Create();
    if (File.Exists(ps1File)) {

        ScriptBlock sb = ScriptBlock.Create(System.IO.File.ReadAllText(ps1File));
        System.Diagnostics.Debug.WriteLine("SB: " + sb.ToString());


        // execute the script and await the result.
        //var results = await ps.InvokeAsync().ConfigureAwait(false);

        //var results = ps.Invoke();

        PSCommand new1 = new PSCommand();
        
        
        ps.Commands = new1;

        var results = ps.Invoke();

        foreach (var result in results)
        {
            Console.WriteLine(result); //<-- result NOT results
            System.Diagnostics.Debug.WriteLine("Error: " + result.ToString());
        }

        System.Diagnostics.Debug.WriteLine("Errors: " + results);
    } else
    {
        System.Diagnostics.Debug.WriteLine("Error: " + "No File");
    }
}

Is there a way to run a PS file and get the windows like from get-credential but without the PowerShell Window?

Thanks Stephan


Edit: It seems, that I have to use exit instead of return to set a correct exit code when I use the first function RunFile, but nevertheless, the inbuild powershell function would be prefered

Stephan
  • 335
  • 3
  • 12

1 Answers1

0

As far as I know, if you calling PowerShell from C# in a way that PowerShell window is not visible, there is no way to display any prompts from that window.

The way we solved this is to ask user for credentials beforehand and pass them as arguments to PS script. You can even pass sensitive data (like password) as SecureString.

using System;
using System.Security;

public static class ConsoleHelper
{
    /// <summary>
    /// Replaces user input with '*' characters
    /// </summary>
    /// <returns>User input as SecureString</returns>
    public static SecureString GetPassword(string message) =>
        GetString(message, GetPasswordReader);

    public static string GetNotEmptyString(string message) =>
        GetString(message, (str) => !string.IsNullOrWhiteSpace(str));

    public static string GetString(string message, Func<string, bool> validator = null) =>
        GetString(message, Console.ReadLine, validator);

    private static T GetString<T>(string message, Func<T> reader, Func<T, bool> validator = null)
    {
        T value;
        while (true)
        {
            Console.Write(message + ": ");
            value = reader();
            if (validator?.Invoke(value) != false)
            {
                break;
            }
        }

        return value;
    }

    private static SecureString GetPasswordReader()
    {
        var pass = new SecureString();
        ConsoleKey key;
        do
        {
            var keyInfo = Console.ReadKey(intercept: true);
            key = keyInfo.Key;

            if (key == ConsoleKey.Backspace && pass.Length > 0)
            {
                Console.Write("\b \b");
                pass.RemoveAt(pass.Length - 1);
            }
            else if (!char.IsControl(keyInfo.KeyChar))
            {
                Console.Write("*");
                pass.AppendChar(keyInfo.KeyChar);
            }
        } 
        while (key != ConsoleKey.Enter);
        Console.WriteLine();

        return pass;
    }
}

Usage example:

var scriptCommand = new Command(formExporterScriptPath)
{
    Parameters =
    {
        { "User", ConsoleHelper.GetNotEmptyString("Enter username") },
        { "Password", ConsoleHelper.GetPassword("Enter password") },
    }
};

using (var powershell = PowerShell.Create())
{
    powershell.Commands.AddCommand(scriptCommand);
    powershell.Invoke();

    Console.ForegroundColor = ConsoleColor.DarkGray;
    foreach (var result in powershell.Streams.Information)
    {
        Console.WriteLine(result.MessageData.ToString());
    }

    if (powershell.Streams.Error.Any())
    {
        Console.ForegroundColor = ConsoleColor.DarkRed;
        foreach (var result in powershell.Streams.Error)
        {
            Console.WriteLine(result.Exception.Message);
        }
    }

    Console.ResetColor();
}
maxc137
  • 2,291
  • 3
  • 20
  • 32