5

I am trying with C# to execute a Powershell file with paramters in a runspace. Unfortunately i get the following output:

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.

What could i do?

Current c# code. this needs to execute commands that will be in a PS file and needs to return a json string.

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 Code:

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

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

Write-Host $date;

exit;
ΩmegaMan
  • 22,885
  • 8
  • 76
  • 94
user2702653
  • 53
  • 1
  • 1
  • 4
  • Can you post the code you're using? – DanM7 Sep 21 '14 at 20:36
  • 1
    Hi, i have added the code. – user2702653 Sep 21 '14 at 20:46
  • Try to remove `Write-Host`, leave just `$date`. `exit` is not needed, too. – Roman Kuzmin Sep 21 '14 at 20:56
  • [code]$date = Get-Date -Format 'h:m:s' | ConvertTo-Json; $date;[/code] Gives the same output. – user2702653 Sep 21 '14 at 21:00
  • 2
    If you want to use cmdlets that require a host you need to create a runspace and pass a PSHost instance. Cmdlets like Write-Host or Read-Host actually require that you also implement PSHostUserInterface that is returned from a property on the PSHost instance. AFAIK there are no default public implementations of these abstract classes. You would have to write them yourself, however [there are some examples available on MSDN.](http://msdn.microsoft.com/en-us/library/ee706577(v=vs.85).aspx) – Mike Zboray Sep 21 '14 at 23:56
  • 3
    For an example of how to implement them (or to just use the ps1 -> exe wrapper) see this blog post - http://rkeithhill.wordpress.com/2010/09/21/make-ps1exewrapper/ – Keith Hill Sep 21 '14 at 23:59

3 Answers3

8

Use Write-Output instead of Write-Host

Liam
  • 22,818
  • 25
  • 93
  • 157
Mike Keysaer
  • 131
  • 2
  • 2
  • I googled, I clicked, I scrolled and saw this answer. I switched from -Host to -Output and stopped getting the error message posted by the OP. This answer is not only correct but also concise and helpful. – Benrobot Aug 16 '16 at 23:14
  • Worked perfect. – Anand Nov 02 '16 at 05:08
5

If you need to run a script that uses non-critical cmdlets like write-host that require the presence of a fully-fledged pshost, you can add "fake" functions to the runspace that either do nothing or log to a text file (or anything else you want.) See my other answer here:

How can I execute scripts in a code created powershell shell that has Write-Host commands in it?

x0n
  • 47,695
  • 5
  • 84
  • 110
1

I have solved this problem myself for Read-Host and Write-Host, by overriding those two cmdlets. In my solution, I silently drop anything sent to Write-Host, but I need to implement Read-Host. This starts a new powershell process and gets the results back.

        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() is, unsurprisingly, my method for executing powershell.

You could easily extend this to implement Write-Host too; let me know if you have any difficulty.

To commenters suggesting switching to Write-Output instead of Write-Host, this is NOT a solution for many use cases. You may not want your user notifications going into your output stream, for example.

Should you need to use the original cmdlets, use this:

Microsoft.PowerShell.Utility\Read-Host -Prompt "Enter your input"
FSCKur
  • 353
  • 1
  • 9