如何从 c# 调用使用“图形命令窗口”(show-command)的 powershell

本文关键字:窗口 show-command powershell 命令 图形 调用 | 更新日期: 2023-09-27 17:52:13

            Collection<PSObject> PSOutput;
            using (PowerShell PowerShellInstance = PowerShell.Create())
            {               
                PowerShellInstance.AddScript("Show-Command -name Get-Content -PassThru");
                PSOutput = PowerShellInstance.Invoke();             
            }

这不返回任何输出,但 PowerShellInstance 上存在错误,其错误流具有空引用异常

在 Microsoft.PowerShell.Command.ShowCommandInternal.ShowCommandHelper.GetHostWindow(PSCmdlet cmdlet( 在 Microsoft.PowerShell.Command.ShowCommandInternal.ShowCommandHelper.CallShowDialog(PSCmdlet cmdlet( 在 Microsoft.PowerShell.Command.ShowCommandInternal.ShowCommandHelper.ShowCommandWindow(PSCmdlet cmdlet, 对象命令视图模型对象, 双窗口宽度, 双精度 窗口高度,布尔直通(

如何从 c# 调用使用“图形命令窗口”(show-command)的 powershell

如果目标是获取 PowerShell CmdLet 的参数,则可以使用 Get-Command。 您将无法从 C# 显示 PowerShell 图形窗口。

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string cmdLetName = "Get-Content";
            Collection<PSObject> PSOutput;
            using (PowerShell PowerShellInstance = PowerShell.Create())
            {
                PowerShellInstance.AddCommand("Get-Command");
                PowerShellInstance.AddParameter("Name", cmdLetName);
                PSOutput = PowerShellInstance.Invoke();
            }
            foreach(var item in PSOutput)
            {
                var cmdLetInfo = item.BaseObject as System.Management.Automation.CmdletInfo;
                var defaultParamSet = cmdLetInfo.ParameterSets.Where(pSet => pSet.IsDefault == true).FirstOrDefault();
                Console.WriteLine(String.Format("Default ParameterSet for {0}.  (*) Denotes Mandatory", cmdLetName));
                foreach (var param in defaultParamSet.Parameters.OrderByDescending(p => p.IsMandatory))
                {
                    if (param.IsMandatory)
                        Console.WriteLine(String.Format("'t {0} (*)", param.Name));
                    else
                        Console.WriteLine(String.Format("'t {0}", param.Name)); ;
                }
            }
            Console.ReadLine();
        }
    }
}

输出:

Default ParameterSet for Get-Content.  (*) Denotes Mandatory
     Path (*)
     ReadCount
     TotalCount
     Tail
     Filter
     Include
     Exclude
     Force
     Credential
     Verbose
     Debug
     ErrorAction
     WarningAction
     InformationAction
     ErrorVariable
     WarningVariable
     InformationVariable
     OutVariable
     OutBuffer
     PipelineVariable
     UseTransaction
     Delimiter
     Wait
     Raw
     Encoding
     Stream

https://blogs.technet.microsoft.com/heyscriptingguy/2012/05/16/use-the-get-command-powershell-cmdlet-to-find-parameter-set-information/

这对我来说看起来像一个错误。 Show-Command 在访问其属性之前不会检查PrivateData是否有null。要解决此问题,您需要实现自己的PSHost,并override PrivateData返回而不是null对象:

Add-Type -TypeDefinition @‘
    using System;
    using System.Globalization;
    using System.Management.Automation;
    using System.Management.Automation.Host;
    public class NotDefaultHost : PSHost {
        private Guid instanceId = Guid.NewGuid();
        private PSObject privateData = new PSObject();
        public override CultureInfo CurrentCulture {
            get {
                return CultureInfo.CurrentCulture;
            }
        }
        public override CultureInfo CurrentUICulture {
            get {
                return CultureInfo.CurrentUICulture;
            }
        }
        public override Guid InstanceId {
            get {
                return instanceId;
            }
        }
        public override string Name {
            get {
                return "NonDefaultHost";
            }
        }
        public override PSObject PrivateData {
            get {
                return privateData;
            }
        }
        public override PSHostUserInterface UI {
            get {
                return null;
            }
        }
        public override Version Version {
            get {
                return new Version(1, 0);
            }
        }
        public override void EnterNestedPrompt() {
            throw new NotSupportedException();
        }
        public override void ExitNestedPrompt() {
            throw new NotSupportedException();
        }
        public override void NotifyBeginApplication() { }
        public override void NotifyEndApplication() { }
        public override void SetShouldExit(int exitCode) { }
    }
’@
$Runspace = [RunspaceFactory]::CreateRunspace((New-Object NotDefaultHost));
$Runspace.Open()
$PS=[PowerShell]::Create()
$PS.Runspace = $Runspace;
$PS.AddScript('Show-Command -Name Get-Content -PassThru').Invoke()
if($PS.HadErrors) {
    '--- Errors: ---'
    $PS.Streams.Error
}
$PS.Dispose()
$Runspace.Dispose()

将其添加到您的代码中:

        Collection<PSObject> PSOutput;
        using (PowerShell PowerShellInstance = PowerShell.Create()) {
            PowerShellInstance.AddScript("Show-Command -name Get-Content -PassThru");
            PSOutput = PowerShellInstance.Invoke();
            if (!PowerShellInstance.HadErrors ) {
                foreach (var item in PSOutput) {
                    Console.WriteLine(item);
                }
            } else {
                foreach (var item in PowerShellInstance.Streams.Error) {
                    Console.WriteLine(item);
                    Console.WriteLine(item.Exception.StackTrace);
                }
            }
        }

返回此输出

Object reference not set to an instance of an object.
   at Microsoft.PowerShell.Commands.ShowCommandInternal.ShowCommandHelper.GetHostWindow(PSCmdlet cmdlet)
   at Microsoft.PowerShell.Commands.ShowCommandInternal.ShowCommandHelper.CallShowDialog(PSCmdlet cmdlet)
   at Microsoft.PowerShell.Commands.ShowCommandInternal.ShowCommandHelper.ShowCommandWindow(PSCmdlet cmdlet, Object commandViewModelObj, Double windowWidth, Double windowHeight, Boolean passThrough)

这几乎表明没有 HostWindow 对象,这是使用 PS 管理对象所期望的。

使用 ILSpy 检查 Microsoft.PowerShell.Commands.Utility.dll 中的代码,似乎Show-Command cmdlet 调用的 ShowCommandProxy 对象正在查找未设置的 System.Management.Automation.Internal GraphicalHostReflectionWrapper 对象。

--更新--

我会看看这个问题:自定义PSHostUserInterface被Runspace忽略,这表明你将不得不实现自己的PSHost(https://msdn.microsoft.com/en-us/library/system.management.automation.host.pshost(v=vs.85(.aspx(并实现你自己的PSHostUserInterface,最后是你自己的PSHostRawUserInterface来处理所有的I/O。

MS 这里有一个示例 https://msdn.microsoft.com/en-us/library/ee706551(v=vs.85(.aspx它执行自定义主机实现。