I'm writing an application that programatically executes PowerShell scripts. This application has a custom PSHost
implementation to allow scripts to output logging statements. Currently, the behavior I'm seeing is that some requests are properly forwarded to my custom PSHost
and others are flat out ignored.
Things get even stranger when I started inspecting the $Host
variable in my scripts, which seem to suggest that my custom PSHost
isn't even being used.
I have some code that's executing PowerShell within a .NET application:
var state = InitialSessionState.CreateDefault();
state.AuthorizationManager = new AuthorizationManager("dummy"); // Disable execution policy
var host = new CustomPsHost(new CustomPsHostUI());
using (var runspace = RunspaceFactory.CreateRunspace(host, state))
{
runspace.Open();
using (var powershell = PowerShell.Create())
{
powershell.Runspace = runspace;
var command = new Command(filepath);
powershell.Invoke(command);
}
}
The implementation for CustomPsHost
is very minimal, only containing what's needed to forward the PSHostUserInterface
:
public class CustomPsHost : PSHost
{
private readonly PSHostUserInterface _hostUserInterface;
public CustomPsHost(PSHostUserInterface hostUserInterface)
{
_hostUserInterface = hostUserInterface;
}
public override PSHostUserInterface UI
{
get { return _hostUserInterface; }
}
// Methods omitted for brevity
}
The CustomPsHostUI is used as a wrapper for logging:
public class CustomPsHostUI : PSHostUserInterface
{
public override void Write(string value) { Debug.WriteLine(value); }
public override void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value){ Debug.WriteLine(value); }
public override void WriteLine(string value) { Debug.WriteLine(value); }
public override void WriteErrorLine(string value) { Debug.WriteLinevalue); }
public override void WriteDebugLine(string message) { Debug.WriteLine(message); }
public override void WriteProgress(long sourceId, ProgressRecord record) {}
public override void WriteVerboseLine(string message) { Debug.WriteLine(message); }
// Other methods omitted for brevity
}
In my PowerShell script, I am trying to write information to the host:
Write-Warning "This gets outputted to my CustomPSHostUI"
Write-Host "This does not get outputted to the CustomPSHostUI"
Write-Warning $Host.GetType().FullName # Says System.Management.Automation.Internal.Host.InternalHost
Write-Warning $Host.UI.GetType().FullName # Says System.Management.Automation.Internal.Host.InternalHostUserInterface
Why am I getting the strange behavior with my CustomPSHostUI
?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With