Michael Sorens
Michael Sorens

Reputation: 36718

How to access PowerShell host from C#

In a PowerShell profile, one can identify the PowerShell host in order to do appropriate setup for that host's environment. For example:

if ($host.Name -eq 'ConsoleHost')
{
    Import-Module PSReadline
    # differentiate verbose from warnings!
    $privData = (Get-Host).PrivateData
    $privData.VerboseForegroundColor = "cyan"
}
elseif ($host.Name -like '*ISE Host')
{
    Start-Steroids
    Import-Module PsIseProjectExplorer
}

I would like to be able to do the equivalent identification from a C# context primarily because PowerShell ISE does not support Console.ReadLine so I want to know if it is safe to use it in the current PS host's environment.

I first explored trying to get the output of the Get-Host cmdlet from within C# (per Invoking a cmdlet within a cmdlet). After I located the Microsoft.PowerShell.Commands.Utility assembly (under C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0) I could compile this but it yielded null...

var cmd = new Microsoft.PowerShell.Commands.GetHostCommand();
var myHost = cmd.Invoke();

...while this would not compile due to the InternalHost class being (ironically!) internal:

var cmd = new Microsoft.PowerShell.Commands.GetHostCommand();
var myHost = cmd.Invoke<System.Management.Automation.Internal.Host.InternalHost>();

Next, I then modified my cmdlet to inherit from PSCmdlet rather than Cmdlet (to allow access to the SessionState), so I could then access the PS host object like this:

var psVarObject = SessionState.PSVariable.GetValue("Host");

Of course, that returns a pure Object, which I then needed to cast to... oh, wait... it's still internal!... so this would not compile:

string psHost = ((System.Management.Automation.Internal.Host.InternalHost)psVarObject).Name;

Leaving me no alternative but to use reflection on a foreign assembly (horrors!):

string psHost = (string)psVarObject.GetType().GetProperty("Name").GetValue(psVarObject, null);

That works, but is less than ideal, because reflecting upon any 3rd-party assembly is a fragile thing to do.

Any alternative ideas on either (a) identifying the host or, (b) backing up a bit, being able to use the host's own Read-Host cmdlet to get a typed input from a user?

Upvotes: 2

Views: 2260

Answers (2)

David Doyle
David Doyle

Reputation: 21

When getting

var psVarObject = SessionState.PSVariable.GetValue("Host");

You can cast it to System.Management.Automation.Host.PSHost instead of InternalHost

Upvotes: 0

user4003407
user4003407

Reputation: 22132

You can just use Host property from PSCmdlet class. And if you want to do Read-Host:

Host.UI.ReadLine()

Upvotes: 3

Related Questions