mercredi 25 février 2015

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?






Aucun commentaire:

Enregistrer un commentaire