C#运行空间Powershell(交互式)

本文关键字:交互式 Powershell 运行 空间 | 更新日期: 2023-09-27 18:23:45

我正在尝试用C#在运行空间中执行一个带有参数的Powershell文件。不幸的是,我得到了以下输出:

提示用户的命令失败,因为主机程序或命令类型不支持用户交互。尝试主机程序支持用户交互,如Windows PowerShell控制台或Windows PowerShell ISE,并从中删除与提示相关的命令不支持用户交互的命令类型,如WindowsPowerShell工作流。

我能做什么?

当前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;

C#运行空间Powershell(交互式)

使用Write-Output而不是Write-Host

如果你需要运行一个使用非关键cmdlet的脚本,比如需要完整pshost的write-host,你可以在运行空间中添加"fake"函数,这些函数要么不做任何事情,要么记录到文本文件(或任何你想要的东西)

如何在代码创建的powershell中执行脚本,其中包含"写入主机"命令?

通过重写这两个cmdlet,我自己为读主机和写主机解决了这个问题。在我的解决方案中,我静默地丢弃任何发送到写主机的内容,但我需要实现读主机。这将启动一个新的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的方法,这不足为奇。

您也可以很容易地将其扩展到实现写主机;如果你有什么困难,请告诉我。

对于建议切换到"写入输出"而不是"写入主机"的评论者来说,这不是许多用例的解决方案。例如,您可能不希望用户通知进入输出流。

如果需要使用原始cmdlet,请使用以下命令:

Microsoft.PowerShell.Utility'Read-Host -Prompt "Enter your input"