Custom PSHostUserInterface is ignored by Runspace

纵饮孤独 提交于 2019-12-04 10:52:35

You need to provide an implementation for PSHostRawUserInterface.

Write-Host ends up calling your version of Write(ConsoleColor, ConsoleColor, string). PowerShell relies on the raw ui implementation for the foreground and background colors.

I have verified this with sample code. Instead of calling out to a ps1 file, I invoked Write-Host directly:

powershell.AddCommand("Write-Host").AddParameter("Testing...")

By running a script, PowerShell was handling the exceptions for you. By invoking the command directly, you can more easily see the exceptions. If you had inspected $error in your original example, you would have seen a helpful error.

Note that the value of $host is never the actual implementation. PowerShell hides the actual implementation by wrapping it. I forget the exact details of why it's wrapped.

For anyone else still struggling after implementing PSHostUserInterface and PSHostRawUserInterface and finding that WriteErrorLine() is being completely ignored when you call Write-Error, even though Warning, Debug, and Verbose make it to the PSHostUserInterface, here's how to get your errors:

Pay close attention to https://msdn.microsoft.com/en-us/library/ee706570%28v=vs.85%29.aspx and add these two lines right before your .Invoke() call, like so:

powershell.AddCommand("out-default");
powershell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output, PipelineResultTypes.Output);

powershell.Invoke() // you had this already

This will merge the Errors stream into your console output, otherwise it apparently doesn't go there. I don't have a detailed understanding of why (so perhaps I shouldn't be implementing a custom PSHost to begin with) but there is some further explanation to be had out there:

http://mshforfun.blogspot.com/2006/07/why-there-is-out-default-cmdlet.html

https://msdn.microsoft.com/en-us/library/system.management.automation.runspaces.command.mergemyresults%28v=vs.85%29.aspx

Also, assuming your host is not a console app, and you're not implementing your own cmd-style character-mode display, you'll need to give it a fake buffer size, because it needs to consult this before giving you the Write-Error output. (Don't give it 0,0, otherwise you get a never-ending torrent of blank lines as it struggles to fit the output into a nothing-sized buffer.) I'm using:

class Whatever : PSHostRawUserInterface
{
    public override Size BufferSize
    {
        get { return new Size(300, 5000); }
        set { }
    }

    ...
}

If you ARE a console app, just use Console.BufferWidth and Console.BufferHeight.

Update: If you'd rather get your errors in ErrorRecord objects rather than lines of pre-formatted error text going to your WriteErrorLine override, hook the PowerShell.Streams.Error.DataAdding event and get the ItemAdded property on the event args. Way less unruly to work with if you're doing something other than simple line-by-line output in your GUI.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!