C# Runspace Powershell (интерактивный)

Я пытаюсь с C# выполнить файл Powershell с параметрами в пространстве выполнения. К сожалению, я получаю следующий вывод:

A command that prompts the user failed because the host program or the command type does not support user interaction. Try a host program that supports user interaction, such as the Windows PowerShell Console or Windows PowerShell ISE, and remove prompt-related commands from command types that do not support user interaction, such as Windows PowerShell workflows.

Что я мог сделать?

Текущий код C#. для этого нужно выполнить команды, которые будут в файле PS и вернуть строку json.

public string ExecuteCommandDirect(int psId, string psMaster, string psFile)
{
    String FullPsFilePath = @"C:\CloudPS\" + psFile + ".ps1";

    String PsParameters = FullPsFilePath + " -psId " + psId + " -psMaster " + psMaster + " -NonInteractive";

    // Create Powershell Runspace
    Runspace runspace = RunspaceFactory.CreateRunspace();

    runspace.Open();

    // Create pipeline and add commands
    Pipeline pipeline = runspace.CreatePipeline();
    pipeline.Commands.AddScript(PsParameters);

    // Execute Script
    Collection<PSObject> results = new Collection<PSObject>();
    try
    {
        results = pipeline.Invoke();
    }
    catch (Exception ex)
    {
        results.Add(new PSObject((object)ex.Message));
    }

    // Close runspace
    runspace.Close();

    //Script results to string
    StringBuilder stringBuilder = new StringBuilder();
    foreach (PSObject obj in results)
    {
        Debug.WriteLine(obj);
        stringBuilder.AppendLine(obj.ToString());
    }

    return stringBuilder.ToString();

}

PS код:

param([int]$psId = 0, [string]$psMaster = 'localhost');

$date = Get-Date -Format 'h:m:s' | ConvertTo-Json;

Write-Host $date;

exit;

3 ответа

Решение

Если вам нужно запустить сценарий, который использует некритические командлеты, такие как write-host, для которых требуется наличие полноценного pshost, вы можете добавить "поддельные" функции в пространство выполнения, которые либо ничего не делают, либо регистрируются в текстовом файле (или все, что вы хотите.) Смотрите мой другой ответ здесь:

Как выполнить сценарии в оболочке powershell, созданной с помощью кода, в которой есть команды Write-Host?

Использование Write-Output вместо Write-Host

Я сам решил эту проблему для Read-Host и Write-Host, переопределив эти два командлета. В моем решении я молча отбрасываю все, что отправлено на Write-Host, но мне нужно реализовать Read-Host. Это запускает новый процесс powershell и возвращает результаты.

        string readHostOverride = @"
            function Read-Host {
                param(
                    [string]$Prompt
                )



                $StartInfo = New-Object System.Diagnostics.ProcessStartInfo
                #$StartInfo.CreateNoWindow = $true 
                $StartInfo.UseShellExecute = $false 
                $StartInfo.RedirectStandardOutput = $true 
                $StartInfo.RedirectStandardError = $true 
                $StartInfo.FileName = 'powershell.exe' 
                $StartInfo.Arguments = @(""-Command"", ""Read-Host"", ""-Prompt"", ""'$Prompt'"")
                $Process = New-Object System.Diagnostics.Process
                $Process.StartInfo = $StartInfo
                [void]$Process.Start()
                $Output = $Process.StandardOutput.ReadToEnd() 
                $Process.WaitForExit() 
                return $Output.TrimEnd()
            }
        ";

        string writeHostOverride = @"
            function Write-Host {
            }
        ";

        Run(readHostOverride);
        Run(writeHostOverride);

Неудивительно, что Run() - мой метод выполнения powershell.

Вы можете легко расширить это для реализации Write-Host; дайте мне знать, если у вас возникнут трудности.

Для комментаторов, предлагающих переключение на Write-Output вместо Write-Host, это НЕ решение для многих случаев использования. Вы, возможно, не хотите, чтобы ваши пользовательские уведомления входили в ваш поток вывода, например.

Если вам нужно использовать оригинальные командлеты, используйте это:

Microsoft.PowerShell.Utility\Read-Host -Prompt "Enter your input"
Другие вопросы по тегам