我该怎么办! (感叹号)何时使用Read-Host?

时间:2016-02-18 21:47:05

标签: powershell

让我们从正常行为开始。当我在没有提示的情况下执行Read-Host时,我可以输入以感叹号开头的字符串:

PS C:\> Read-Host | Foreach-Object { Write-Host 'Entered' $_ }
!hi, mom
Entered !hi, mom

(请注意,我只管道Foreach-Object作为输出前缀的简单方法。如果你在没有它的情况下执行Read-Host,感兴趣的行为是相同的。)

但如果我给Read-Host一个提示参数,那么行为就完全不同了:

PS C:\> Read-Host 'Enter something' | Foreach-Object { Write-Host 'Entered' $_ }
Enter something: !hi, mom
"!hi, mom" cannot be recognized as a valid Prompt command.
Enter something: !!hi, mom
Entered !hi, mom

似乎感叹号允许我除了输入一个字符串之外还做一些事情。 PowerShell正在解释感叹号意味着我正在输入某种命令让它运行,但我找不到任何关于允许的内容的文档。除了将感叹号加倍以逃避它之外,我无法弄清楚是一个有效的命令。

请注意,输入必须开始并带有感叹号。结束它不会触发此行为:

PS C:\> Read-Host 'Enter something' | Foreach-Object { Write-Host 'Entered' $_ }
Enter something: hi, mom!
Entered hi, mom!

那么我可以在这里使用!做什么?什么一个有效的命令,除了逃避感叹号?解决方法很有用,但我实际上想知道我是否可以在这里执行代码。

我正在使用PowerShell 4,但这似乎更早date back

3 个答案:

答案 0 :(得分:6)

<强> TL;博士

  • Read-Host,顾名思义,是特定于主机的

    • 自PSv5.1起, 标准控制台主机(控制台窗口)和PSv3 +中的,ISE 表现出意外行为。 (在PSv2-中,ISE使用了自己的GUI Read-Host提示符,但没有受到影响。
  • 该行为实际上是 无关的功能,似乎意外暴露,即{strong> {{1}指定了提示字符串参数(Read-Host)。

    • 鉴于行为未记录以这种模糊方式公开,应将其视为错误
  • 解决错误,如下所示:

    • -Prompt
    • 即:使用Write-Host -NoNewline 'Enter something: '; Read-Host分别打印提示字符串,预先(没有换行符),然后调用Write-Host 而不用 { {1}}参数:

要回答问题的标题,&#34;我该怎么办!什么时候使用Read-Host?&#34;:什么都没用 要了解原因和背景信息,请继续阅读。

行为 - 以及对它的抱怨 - 可以追溯到PowerShell的第一个版本;在post also linked to by the OP,MS员工称之为&#34;提示命令&#34; ,其中一位架构师更详细地解释了here @TheMadTechnician在评论问题 请注意,在PowerShell 本身如何提示缺少必需参数值 的上下文中讨论,其中 应该< / em>与Read-Host

没有的关系

当系统提示您输入未在命令行中指定的必需参数值时(以及使用-PromptRead-Host时也出乎意料),Read-Host为< em>第一个字符(仅)启动&#34;提示命令&#34;:

  • -Prompt为手头参数(描述)调用帮助字符串。

    • !的上下文中,提示字符串(!)被解释为寻求帮助的参数名称,因此找不到帮助(!?)。
  • Read-Host允许输入空字符串作为数组参数的参数值,同时允许输入其他值(只需按Enter键即可终止提示)。

    • No help is available for <prompt-string>的上下文中,这只是输出一个空字符串。
  • !""允许输入文字 Read-Host

  • Χpẘ's great answer使用基础程序集的反汇编来表明,至少从PS v3开始,不支持其他命令。

linked forum post得出结论(强调我的):

  

请注意,这是当前实现的工件   在PowerShell主机中提示。它不是核心引擎的一部分。一个    GUI主机不太可能使用此表示法。一个合理   增强功能是允许提示命令   用户可配置的

10年后,行为 - 至少在!!的背景下 - 既没有记录也没有可配置。

在发现上述帖子之前,jpmc26自己发现该行为与PowerShell 本身如何提示缺少必需参数有关; e.g:

!

答案 1 :(得分:3)

使用JetBrains dotPeek我找到了'!'的实现被处理。它位于程序集Microsoft.PowerShell.ConsoleHostUserInterface.PromptCommandMode中的Microsoft.Powershell.ConsoleHost中。这是PS 3.0。反汇编的代码如下。

strA.StartsWith的检查必须是查看'!'被另一个'!'逃脱了。

请注意,检查strA[0] == 63是否检查'?' (0x3F的)。任何其他单个字符输入都会在OP中产生错误消息。两个双引号产生空字符串(这是Bruce Payette在OP注释中引用的链接中所说的),字符串'$null'产生$null

其他任何内容都会显示相同的错误消息。因此,如果没有某种代理或写主持人,'!'不能真正用于其他命令。

private string PromptCommandMode(string input, FieldDescription desc, out bool inputDone)
{
  string strA = input.Substring(1);
  inputDone = true;
  if (strA.StartsWith("!", StringComparison.OrdinalIgnoreCase))
    return strA;
  if (strA.Length == 1)
  {
    if ((int) strA[0] == 63)
    {
      if (string.IsNullOrEmpty(desc.HelpMessage))
      {
        string str = StringUtil.Format(ConsoleHostUserInterfaceStrings.PromptNoHelpAvailableErrorTemplate, (object) desc.Name);
        ConsoleHostUserInterface.tracer.TraceWarning(str);
        this.WriteLineToConsole(this.WrapToCurrentWindowWidth(str));
      }
      else
        this.WriteLineToConsole(this.WrapToCurrentWindowWidth(desc.HelpMessage));
    }
    else
      this.ReportUnrecognizedPromptCommand(input);
    inputDone = false;
    return (string) null;
  }
  if (strA.Length == 2 && string.Compare(strA, "\"\"", StringComparison.OrdinalIgnoreCase) == 0)
    return string.Empty;
  if (string.Compare(strA, "$null", StringComparison.OrdinalIgnoreCase) == 0)
    return (string) null;
  this.ReportUnrecognizedPromptCommand(input);
  inputDone = false;
  return (string) null;
}

private void ReportUnrecognizedPromptCommand(string command)
{
  this.WriteLineToConsole(this.WrapToCurrentWindowWidth(StringUtil.Format(ConsoleHostUserInterfaceStrings.PromptUnrecognizedCommandErrorTemplate, (object) command)));
}

答案 2 :(得分:2)

这是拼图的另一部分 我正在运行V5,它可以在ISE中运行:

PS C:\> $PSVersionTable


Name                           Value                                                                                                  
----                           -----                                                                                                  
PSVersion                      5.0.10586.51                                                                                           
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                
BuildVersion                   10.0.10586.51                                                                                          
CLRVersion                     4.0.30319.34209                                                                                        
WSManStackVersion              3.0                                                                                                    
PSRemotingProtocolVersion      2.3                                                                                                    
SerializationVersion           1.1.0.1       

PS C:\> Read-Host 'Enter something' | Foreach-Object { Write-Host 'Entered' $_}
Enter something: !Hi, mom
Entered !Hi, mom

但它无法在正常的命令提示符下运行:

PS C:\> Read-Host 'Enter something' | Foreach-Object { Write-Host "Entered $_"}
Enter something: !Hi, mom
"!Hi, mom" cannot be recognized as a valid Prompt command.
Enter something: