如何在C#中获取PowerShell的Get-Command的“建议”?

时间:2018-10-24 17:40:05

标签: c# powershell

如果我创建一个名为“ dir.exe”的文件并运行PowerShell命令Get-Command dir -Type Application,我会得到错误消息,因为dir不是应用程序(尽管该文件存在):

gcm : The term 'dir' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:2
+ (gcm dir -Type Application)
+  ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (dir:String) [Get-Command], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand


Suggestion [3,General]: The command dir was not found, but does exist in the current location. Windows PowerShell does not load commands from the current location by default. If you trust this command, instead type: ".\dir". See "get-help about_Command_Precedence" for more details.

注意底部的SuggestionSuggestion [3,General]: The command dir was not found, but does exist in the current location. Windows PowerShell does not load commands from the current location by default. If you trust this command, instead type: ".\dir". See "get-help about_Command_Precedence" for more details.

我正试图在我的C#代码中捕捉到该建议:

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Automation;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Helpers.Tests {
    [TestClass]
    public class PowerShellRunner_Tests {
        [TestMethod]
        public void GetCommand_Test() {
            // create file called "dir.exe" to see how PowerShell handles
            // "Get-Command dir -Type Application":
            File.Create("dir.exe").Dispose();               

            using (PowerShell powerShell = PowerShell.Create()) {
                powerShell.AddCommand("get-command")
                    .AddArgument("dir")
                    .AddParameter("Type", CommandTypes.Application.ToString());

                // run "Get-Command dir -Type Application":
                CommandInfo commandInfo = powerShell.Invoke<CommandInfo>().FirstOrDefault();

                // get the error:
                ErrorRecord error = powerShell.Streams.Error.FirstOrDefault();

                // emit the "Suggestion":
                Trace.WriteLine(error.ErrorDetails.RecommendedAction);
            }
        }
    }
}

但是error.ErrorDetailsnull。我怎么能得到Suggestion

(我试图获得where.exe的行为,但没有为此麻烦运行整个过程的麻烦。)

1 个答案:

答案 0 :(得分:2)

鉴于最终目标是模仿where.exe的行为,请尝试以下操作:

(Get-Command -Type Application .\dir, dir -ErrorAction Ignore).Path

请注意使用-Type Application将结果限制为可执行文件,并排除PowerShell内部命令(例如函数和别名)。

where.exe一样,它会先在当前目录 中查找。 仅提供名称,例如dirGet-Command不在当前目录中查找,因为PowerShell不允许通过 name调用当前目录中的可执行文件仅-出于安全原因;但是,使用相对路径.\会使Get-Command找到这样的可执行文件。

但是,从cmd.exe开始-假设其行为where.exe-仅使用dir.exe(仅按名称)调用仅当前目录的dir即可。

如果输出只是一个一个路径,并且该路径是当前目录中的文件,则可以推断出dir可执行文件存在 ,这是PowerShell发出建议以在调用时使用显式路径的条件。

$fullPaths = (Get-Command -Type Application .\dir, dir -ErrorAction Ignore).Path
$emitSuggestion = $fullPaths.Count -eq 1 -and 
                  (Test-Path ('.\' + (Split-Path -Leaf $fullPaths[0]))

注意:严格来说,您还应排除当前目录恰好是$env:PATH中列出的目录的情况:
$env:PATH -split ';' -ne '' -notcontains (Split-Path -Parent $fullPaths[0])

您可以通过Write-Error向错误流中写入建议的自定义版本,或者最好向{em> warning 流中使用{{1 }}。


要通过PowerShell SDK使用上述命令,最简单的方法是使用Write-Warning方法;例如:

.AddScript()

关于捕获或隐藏PowerShell的建议:

不幸的是,您无法以编程方式获得对建议的访问权限(自Windows PowerShell v5.1 / PowerShell Core 6.1.0起编写):

与您一样,使用PowerShell SDK会涉及PowerShell default host,而PowerShell console host基本上不会发出建议。

只有{{3}}(在控制台(终端)窗口中使用)发出建议,但是即使建议被直接直接打印到屏幕,绕过PowerShell的输出流系统。

简而言之:建议仅显示在控制台窗口(终端)中,并且只能查看,而不能在其中捕获。


在控制台窗口中快速演示建议的行为(假设Windows,在当前目录中有一个名为powerShell.AddScript("(Get-Command -Type Application .\dir, dir -ErrorAction Ignore).Path"); 的文件,在dir.exe中也没有):

$env:PATH

如您所见,尽管尝试抑制所有 输出(PS> & { try { Get-Command dir.exe } catch {} } *>$null Suggestion [3,General]: The command dir.exe was not found, but does exist in the current location. Windows PowerShell does not load commands from the current location by default. If you trust this command, instead type: ".\dir.exe". See "get-help about_Command_Precedence" for more details. ),但该建议仍会显示在屏幕上,这也意味着您不能捕获建议。

但是,存在 是一种沉默建议的方法,即使用*>$null (PSv3 +);相反,使用-ErrorAction Ignore时,该建议仍会打印(!):

-ErrorAction SilentlyContinue
相关问题