【问题标题】:Get-Help for .trim / -trim, .replace / -replace, .split / -split and other string operators.trim / -trim、.replace / -replace、.split / -split 和其他字符串运算符的获取帮助
【发布时间】:2019-12-06 11:27:54
【问题描述】:

PowerShell 有一个非常好的内置帮助系统,我经常使用它,我可以使用 Get-Help * 查看所有帮助选项并查询 Cmdlet,或者可以使用 Get-Help about_* 查找主题,然后说 Get-Help about_compar*打开 Comparison Operators 话题,一切都很好。

但是,我试图找到有关各种字符串运算符的帮助,例如 .replace、.compare、.split、.substring。有谁知道如何在 PowerShell 控制台上提取这些主题(它们可能隐藏在一些 about_* 主题中,但我不知道在哪里看)?

此外,字符串运算符有 -replace、-compare、-split 变体等,虽然与 .replace 等几乎相同,但一个版本使用正则表达式,另一个不使用。有谁知道是否有帮助主题(同样,可从控制台获得!)澄清所有这些?如果 PowerShell 帮助系统在其内置帮助系统中缺少对所有这些的说明,则会感觉非常缺乏,因为这些是语言中使用非常频繁的部分(所以希望这一切都隐藏在我的一些 about_* 主题中) '还没有找到)。

【问题讨论】:

  • .Replace()、.Split() 方法在 .NET System.String 类中。它们不是 PowerShell 命令。因此,它们没有典型的Get-Help 页面。我知道这不会为您提供您正在寻找的答案,但最简单的方法就是转到 System.String 并展开方法。
  • 我通常做的是$i='mystring',然后是$i.Split。这给了我Split 的所有不同变体。或者我在线查看 MS 文档,即 docs.microsoft.com/en-us/dotnet/api/… 。在 Powershell 中我只找到了这个命令 get-help about_methods -full 但它对我没有多大帮助..
  • 感谢 Dan,正如您所说,$i.split(和 $i | Get-Member)给了我很多东西,然后我就可以遍历方法。这对 .replace()、.split() 很有用,因为在控制台上看到 OverloadDefinitions 非常有用。关于在控制台上获取 -replace()、-split() 表单的信息有什么想法吗?啊,我还看到诸如“System.StringSplitOptions 选项”之类的东西,就有效的拆分选项可能是什么而言,这并不是非常有用的信息。
  • 好点 AdminOfThings,我没有意识到这一点。您认为我们可以在控制台上做些什么来从System.String 类中提取信息吗?
  • @roysubs [Enum]::GetNames([StringSplitOptions]) 会有所帮助。

标签: string powershell console operators help-system


【解决方案1】:
  • 如前所述,方法 .NET 类型(例如 System.String.Split())不是 PowerShell 的一部分,而是 .NET PowerShell 所基于的框架,因此您必须参阅https://docs.microsoft.com的官方文档。

  • 也就是说,鉴于 PowerShell 和 .NET 之间的紧密集成,如果能够从 PowerShell 中轻松查阅此文档,那就太好了 - 请参阅 this GitHub suggestion。

  • 但是,操作符,例如 -split 是 PowerShell 语言功能,并且既要完全发现它们的文档,又要集中注意力,特定于操作符的信息目前很麻烦。

    • 诸如运算符之类的语言功能的文档包含在about_* 帮助主题中,可以使用Get-Help -Category HelpFile 作为目标,您可以将其与传递运算符的(带引号的)名称结合起来以搜索 这些主题的内容:

      • 例如,Get-Help -Category HelpFile -Name '-replace' 至少缩小了搜索范围,但仍包含所有提及 -replace 的帮助主题;结果将包含 about_Operators 帮助主题,这是一个概述页面,它链接到更具体的页面,专注于特定的运算符类别,例如算术运算符、比较运算符, ...,但也直接描述了一些通用运算符。
  • 目前没有直接的方法来获取给定运算符的重点信息,但应该有:请参阅this GitHub suggestion。


下面是两个帮助函数,它们试图克服当前的限制(从 v7.0 开始),Show-OperatorHelp 和 Show-TypeHelp。

注意:

  • 这两个函数(必须)都不在控制台中显示文档(终端),而是在您的默认网络浏览器中打开在线文档。

    • 在 Show-TypeHelp 中,支持仅限于 .NET 附带的那些(公共)类型,因此在 https://docs.microsoft.com 有文档页面。

    • Show-OperatorHelp 尽可能打开仅描述感兴趣的运算符的特定部分;一些运算符,例如算术运算符+、-,没有单独的部分,但在这些情况下,整个主题通常足够短,以便于找到感兴趣的部分。

  • 它们带有基于评论的帮助,因此您可以使用 -? 和 Get-Help 了解更多信息。

  • 例如,您可以将它们放在您的 $PROFILE 文件中,或者 - 考虑到它们的长度 - 您可能希望基于它们创建 外部脚本 (*.ps1),然后将它们放在$env:Path 中列出的目录。为此,只需剥离function <name> { 行和最后的} 并将它们保存到*.ps1 文件中。

使用示例:

Show-OperatorHelp:

# Opens the home (overview) page for all PowerShell operators
Show-OperatorHelp

# Lists all operators in the console, 
# along with their friendly names and categories.
Show-OperatorHelp -List

# Opens the help topic (section) for the -replace operator.
# Equivalent of 
    Show-OperatorHelp -Name '-replace'
# because you omit the initial '-'; if you do specify it, quote the entire argument.
Show-OperatorHelp replace

# Opens the help topic (section) for @(...), the array-subexpression operator.
# Note the need for quoting.
Show-OperatorHelp '@()'

Show-TypeHelp:

# Opens the documentation for the System.String.Split() method.
#  You can specify a type name ('string' in this example) as follows:
#    * Use a full type name, with the initial 'System.' component optionally omitted (e.g. 'Text.Encoding' for 'System.Text.Encoding'
#    * Use a type accelerator such as 'xml' for 'System.Xml.XmlDocument'
# Tab-completion: You can type (part of) a the name of a type
# (last component of the full name) and cycle through loaded types by that name.
# E.g., typing `arrayli` tab-completes to 'System.Collections.ArrayList'.
# Alternatively, *pipe* an instance of a string to the function (see next example).
Show-TypeHelp string split # Short for: Show-TypeHelp -Type string -Member split

# Opens the documentation for the [Microsoft.PowerShell.Commands.MatchInfo]
# type, instances of which Select-String outputs.
'foo' | Select-String o | Show-TypeHelp

我建议改为从以下 MIT 许可的 Gists 获取源代码,因为只有它们会被维护;假设您已经查看了代码(我个人可以向您保证是安全的,但您应该经常检查),您可以直接安装它们:

irm https://gist.github.com/mklement0/146f3202a810a74cb54a2d353ee4003f/raw/Show-OperatorHelp.ps1 | iex

irm https://gist.github.com/mklement0/50a1b101cd53978cd147b4b138fe6ef4/raw/Show-TypeHelp.ps1 | iex

注意:忽略下面突出显示的损坏语法。

Show-OperatorHelp源码:

function Show-OperatorHelp {
  <#
.SYNOPSIS
Shows documentation for PowerShell's operators.

.DESCRIPTION
Navigates to operator-specific or -related online help topics in your default 
web browser.

Invoke argument-less to see the operators overview help topic.
-Precedence shows the topic about operator precedence.
-QuotingRules shows the topic about string literals and quoting.
-Name <name> targets a specific operator.

.PARAMETER Name
The name of an operator.

Note that most names must be passed *in quotes* for syntactic reasons;
e.g., '-match' instead of -match
However, you may omit the initial '-', in which case you needn't quote.

Use -List to see all names.

.PARAMETER Precedence
Opens the help topic that describes operator precedence.

.PARAMETER List
Parameter description

.PARAMETER QuotingRules
Opens the help topic that describes the quoting rules and syntax for
string literals.

.PARAMETER CopyUrl
Instead of opening the topic page in a browser, copies the page's URL to
the clipboard.

.PARAMETER Version
Specify a specific PowerShell version number (e.g., 7 or 5.1) for which to
display the requested help topic.
By default, the executing engine's version number is used.

.EXAMPLE
Show-OperatorHelp

Opens the home (overview) page for all PowerShell operators.

.EXAMPLE
Show-OperatorHelp replace

Opens the help topic (section) for the -replace operator.
Equivalent of: Show-OperatorHelp -Name '-replace'

.EXAMPLE
Show-OperatorHelp -List

Lists all operators, along with their friendly names and categories.

.EXAMPLE
Show-OperatorHelp -Precedence

Shows the help topic about operator precedence.
#>

  [CmdletBinding(DefaultParameterSetName = 'HomePage', SupportsShouldProcess, PositionalBinding = $false)]
  param (
    [Parameter(ParameterSetName = 'Name', Mandatory, Position = 0)]
    [string] $Name
    ,
    [Parameter(ParameterSetName = 'Precedence')]
    [switch] $Precedence
    ,
    [Parameter(ParameterSetName = 'List')]
    [Alias('ListAvailable')]
    [switch] $List
    ,
    [Parameter(ParameterSetName = 'QuotingRules')]
    [Alias('StringLiterals')]
    [switch] $QuotingRules
    ,
    [Parameter(ParameterSetName = 'Name')]
    [Parameter(ParameterSetName = 'Precedence')]
    [Parameter(ParameterSetName = 'QuotingRules')]
    [Parameter(ParameterSetName = 'HomePage')]
    [Alias('cp')]
    [switch] $CopyUrl
    ,
    [Parameter(ParameterSetName = 'Name')]
    [Parameter(ParameterSetName = 'Precedence')]
    [Parameter(ParameterSetName = 'QuotingRules')]
    [Parameter(ParameterSetName = 'HomePage')]
    [string] $Version # PowerShell version
  )

  # Default to the executing PowerShell engine's version.
  # Note: If no "?view=powershell-<ver>" query string is present,
  #       the currently highest stable version overall is targeted.
  if ($Version) {
    $verObj = $Version -as [version]
    if (-not $verObj) { $verObj = "$Version.0" -as [version] }
    if (-not $verObj) { Throw "Unrecognized PowerShell version number: $Version" }
  }
  else {
    $verObj = $PSVersionTable.PSVersion
  }
  $Version = ('{0}.{1}' -f $verObj.Major, $verObj.Minor) -replace '\.0$'

  $opTable = @{
    # about_Arithmetic_Operators
    '-'            = [pscustomobject] @{ Name = '-'; FriendlyName = 'subtraction / sign inversion'; Topic = 'about_Arithmetic_Operators'; Category = 'Arithmetic' } 
    '*'            = [pscustomobject] @{ Name = '*'; FriendlyName = 'multiplication / string replication'; Topic = 'about_Arithmetic_Operators'; Category = 'Arithmetic' } 
    '/'            = [pscustomobject] @{ Name = '/'; FriendlyName = 'division'; Topic = 'about_Arithmetic_Operators'; Category = 'Arithmetic' } 
    '%'            = [pscustomobject] @{ Name = '%'; FriendlyName = 'modulus'; Topic = 'about_Arithmetic_Operators'; Category = 'Arithmetic' } 
    '+'            = [pscustomobject] @{ Name = '+'; FriendlyName = 'addition / string conatenation'; Topic = 'about_Arithmetic_Operators'; Category = 'Arithmetic' } 
    '-band'        = [pscustomobject] @{ Name = '-band'; FriendlyName = 'bitwise AND'; Topic = 'about_Arithmetic_Operators'; Category = 'Bitwise' } 
    '-bor'         = [pscustomobject] @{ Name = '-bor'; FriendlyName = 'bitwise OR'; Topic = 'about_Arithmetic_Operators'; Category = 'Bitwise' } 
    '-bxor'        = [pscustomobject] @{ Name = '-bxor'; FriendlyName = 'bitwise XOR'; Topic = 'about_Arithmetic_Operators'; Category = 'Bitwise' } 
    '-bNot'        = [pscustomobject] @{ Name = '-bNot'; FriendlyName = 'bitwise complement'; Topic = 'about_Arithmetic_Operators'; Category = 'Bitwise' } 
    # about_Assignment_Operators
    '='            = [pscustomobject] @{ Name = '='; FriendlyName = 'assignment'; Topic = 'about_Assignment_Operators'; Category = 'Assignment' } 
    '+='           = [pscustomobject] @{ Name = '+='; FriendlyName = 'compound assignment'; Topic = 'about_Assignment_Operators'; Category = 'Assignment' } 
    '-='           = [pscustomobject] @{ Name = '-='; FriendlyName = 'compound assignment'; Topic = 'about_Assignment_Operators'; Category = 'Assignment' } 
    '*='           = [pscustomobject] @{ Name = '*='; FriendlyName = 'compound assignment'; Topic = 'about_Assignment_Operators'; Category = 'Assignment' } 
    '/='           = [pscustomobject] @{ Name = '/='; FriendlyName = 'compound assignment'; Topic = 'about_Assignment_Operators'; Category = 'Assignment' } 
    '%='           = [pscustomobject] @{ Name = '%='; FriendlyName = 'compound assignment'; Topic = 'about_Assignment_Operators'; Category = 'Assignment' } 
    '++'           = [pscustomobject] @{ Name = '++'; FriendlyName = 'increment'; Topic = 'about_Assignment_Operators'; Category = 'Assignment' } 
    '--'           = [pscustomobject] @{ Name = '--'; FriendlyName = 'decrement'; Topic = 'about_Assignment_Operators'; Category = 'Assignment' } 
    # about_Comparison_Operators
    '-eq'          = [pscustomobject] @{ Name = '-eq'; FriendlyName = 'equality'; Topic = 'about_Comparison_Operators'; Anchor = '-eq'; Category = 'Equality' } 
    '-ne'          = [pscustomobject] @{ Name = '-ne'; FriendlyName = 'inequality'; Topic = 'about_Comparison_Operators'; Anchor = '-ne'; Category = 'Equality' } 
    '-gt'          = [pscustomobject] @{ Name = '-gt'; FriendlyName = 'greater-than'; Topic = 'about_Comparison_Operators'; Anchor = '-gt'; Category = 'Equality' } 
    '-ge'          = [pscustomobject] @{ Name = '-ge'; FriendlyName = 'greater-than-or-equal'; Topic = 'about_Comparison_Operators'; Anchor = '-gt'; Category = 'Equality' } 
    '-lt'          = [pscustomobject] @{ Name = '-lt'; FriendlyName = 'less-than'; Topic = 'about_Comparison_Operators'; Anchor = '-lt'; Category = 'Equality' } 
    '-le'          = [pscustomobject] @{ Name = '-le'; FriendlyName = 'less-than-or-equal'; Topic = 'about_Comparison_Operators'; Anchor = '-le'; Category = 'Equality' } 
    '-like'        = [pscustomobject] @{ Name = '-like'; FriendlyName = 'wildcard matching'; Topic = 'about_Comparison_Operators'; Anchor = '-like'; Category = 'Matching' } 
    '-notlike'     = [pscustomobject] @{ Name = '-notlike'; FriendlyName = 'negated wildcard matching'; Topic = 'about_Comparison_Operators'; Anchor = '-notlike'; Category = 'Matching' } 
    '-match'       = [pscustomobject] @{ Name = '-match'; FriendlyName = 'regular-expression matching'; Topic = 'about_Comparison_Operators'; Anchor = '-match'; Category = 'Matching' } 
    '-notmatch'    = [pscustomobject] @{ Name = '-notmatch'; FriendlyName = 'negated regular-expression matching'; Topic = 'about_Comparison_Operators'; Anchor = '-notmatch'; Category = 'Matching' } 
    '-replace'     = [pscustomobject] @{ Name = '-replace'; FriendlyName = 'regular-expression-based string replacement'; Topic = 'about_Comparison_Operators'; Anchor = 'replacement-operator'; Category = 'String' } 
    '-in'          = [pscustomobject] @{ Name = '-in'; FriendlyName = 'LHS contained in RHS'; Topic = 'about_Comparison_Operators'; Anchor = '-in'; Category = 'Containment' } 
    '-notIn'       = [pscustomobject] @{ Name = '-notIn'; FriendlyName = 'LHS not contained in collection'; Topic = 'about_Comparison_Operators'; Anchor = '-notin'; Category = 'Containment' } 
    '-contains'    = [pscustomobject] @{ Name = '-contains'; FriendlyName = 'collection contains RHS'; Topic = 'about_Comparison_Operators'; Anchor = '-contains'; Category = 'Containment' } 
    '-notContains' = [pscustomobject] @{ Name = '-notContains'; FriendlyName = 'collection doesn''t contain RHS'; Topic = 'about_Comparison_Operators'; Anchor = '-notcontains'; Category = 'Containment' } 
    # about_Join
    '-join'        = [pscustomobject] @{ Name = '-join'; FriendlyName = 'string joining'; Topic = 'about_Join'; Category = 'String' } 
    # about_Split
    '-split'       = [pscustomobject] @{ Name = '-split'; FriendlyName = 'string splitting'; Topic = 'about_Split'; Category = 'String' } 
    # about_Logical_Operators
    '-not'         = [pscustomobject] @{ Name = '-not'; FriendlyName = 'logical NOT'; Topic = 'about_Logical_Operators'; Category = 'Logical' } 
    '!'            = [pscustomobject] @{ Name = '!'; FriendlyName = 'logical NOT'; Topic = 'about_Logical_Operators'; Category = 'Logical' } 
    '-and'         = [pscustomobject] @{ Name = '-and'; FriendlyName = 'logical AND'; Topic = 'about_Logical_Operators'; Category = 'Logical' } 
    '-or'          = [pscustomobject] @{ Name = '-or'; FriendlyName = 'logical OR'; Topic = 'about_Logical_Operators'; Category = 'Logical' } 
    '-xor'         = [pscustomobject] @{ Name = '-xor'; FriendlyName = 'logical XOR'; Topic = 'about_Logical_Operators'; Category = 'Logical' } 
    # about_Operators
    '$()'          = [pscustomobject] @{ Name = '$()'; FriendlyName = 'subexpression'; Topic = 'about_Operators'; Anchor = 'subexpression-operator--'; Category = 'Evaluation' } 
    '@()'          = [pscustomobject] @{ Name = '@()'; FriendlyName = 'array-subexpression'; Topic = 'about_Operators'; Anchor = 'array-subexpression-operator--'; Category = 'Evaluation' } 
    '()'           = [pscustomobject] @{ Name = '()'; FriendlyName = 'grouping'; Topic = 'about_Operators'; Anchor = 'grouping-operator--'; Category = 'Evaluation' } 
    '. '           = [pscustomobject] @{ Name = '.'; FriendlyName = '(dot-)source'; Topic = 'about_Operators'; Anchor = 'dot-sourcing-operator-'; Category = 'Execution' }   # Sadly, we have to use '. ' to distinguish it from the member-access operator
    '&'            = [pscustomobject] @{ Name = '&'; FriendlyName = 'call (execute)'; Topic = 'about_Operators'; Anchor = 'call-operator-'; Category = 'Execution' }
    ' &'           = [pscustomobject] @{ Name = '&'; FriendlyName = 'background'; Topic = 'about_Operators'; Anchor = 'background-operator-'; Category = 'Execution' } # Sadly, we have to use ' &' to distinguish it from the call operator
    '&&'           = [pscustomobject] @{ Name = '&&'; FriendlyName = 'pipeline-chain AND'; Topic = 'about_Pipeline_Chain_Operators'; Category = 'Pipeline' }
    '||'           = [pscustomobject] @{ Name = '||'; FriendlyName = 'pipeline-chain OR'; Topic = 'about_Pipeline_Chain_Operators'; Category = 'Pipeline' }
    '|'            = [pscustomobject] @{ Name = '|'; FriendlyName = 'pipeline'; Topic = 'about_Operators'; Anchor = 'pipeline-operator-'; Category = 'Pipeline' }
    '.'            = [pscustomobject] @{ Name = '.'; FriendlyName = 'member access'; Topic = 'about_Operators'; Anchor = 'member-access-operator-'; Category = 'Object' } 
    '::'           = [pscustomobject] @{ Name = '::'; FriendlyName = 'static member access'; Topic = 'about_Operators'; Anchor = 'static-member-operator-'; Category = 'Object' } 
    '[0]'          = [pscustomobject] @{ Name = '[0]'; FriendlyName = 'index'; Topic = 'about_Operators'; Anchor = 'index-operator--'; Category = 'Object' } 
    '[int]'        = [pscustomobject] @{ Name = '[int]'; FriendlyName = 'cast / type constraint'; Topic = 'about_Operators'; Anchor = 'cast-operator--'; Category = 'Type' } 
    ','            = [pscustomobject] @{ Name = ','; FriendlyName = 'array constructor'; Topic = 'about_Operators'; Anchor = 'comma-operator-'; Category = 'Array' } 
    '..'           = [pscustomobject] @{ Name = '..'; FriendlyName = 'range (numbers/characters) '; Topic = 'about_Operators'; Anchor = 'range-operator-'; Category = 'Array' } 
    '-f'           = [pscustomobject] @{ Name = '-f'; FriendlyName = 'format (strings)'; Topic = 'about_Operators'; Anchor = 'format-operator--f'; Category = 'String' } 
    '?:'           = [pscustomobject] @{ Name = '?:'; FriendlyName = 'ternary conditional'; Topic = 'about_Operators'; Anchor = 'ternary-operator--if-true--if-false'; Category = 'Conditional' } 
    '??'           = [pscustomobject] @{ Name = '??'; FriendlyName = 'null-coalescing'; Topic = 'about_Operators'; Anchor = ''; Category = 'Conditional' } # ?? Not yet covered in the v7 topic as of 12 Dec 2019
    # about_Redirection
    '>'            = [pscustomobject] @{ Name = '>'; FriendlyName = 'redirection'; Topic = 'about_Redirection'; Category = 'Stream' }
    '>>'           = [pscustomobject] @{ Name = '>>'; FriendlyName = 'appending redirection'; Topic = 'about_Redirection'; Category = 'Stream' }
    # about_Type_Operators
    '-is'          = [pscustomobject] @{ Name = '-is'; FriendlyName = 'type(-inheritance) / interface test'; Topic = 'about_Type_Operators'; Category = 'Type' } 
    '-isnot'       = [pscustomobject] @{ Name = '-isnot'; FriendlyName = 'negated type(-inheritance) / interface test'; Topic = 'about_Type_Operators'; Category = 'Type' } 
    '-as'          = [pscustomobject] @{ Name = '-as'; FriendlyName = 'conditional type conversion'; Topic = 'about_Type_Operators'; Category = 'Type' } 
    # --- Not covered by an operator help topic, but could be considered one.
    # about_Splatting
    '@'            = [pscustomobject] @{ Name = '@'; FriendlyName = 'splatting (arguments)'; Topic = 'about_Splatting'; Category = 'Splatting' } 
  }

  # As a courtesy, interpret variations of quotes / quoting styles passed as -Name as if -Quoting had been passed instead.
  $parameterSetNameInEffect = $PSCmdlet.ParameterSetName
  if ($Name -replace '\s' -match '^(?:''''?|""?|@''(''@)?|@"("@)?)$') {
    $parameterSetNameInEffect = 'QuotingRules'  
  }

  $url = ''

  switch ($parameterSetNameInEffect) {

    'Name' {

      $warning = ''

      # See if the name matches an entry as-is.
      $entry = $opTable[$Name]

      # If '.' was passed, warn about member-access / dot-sourcing ambiguity.
      if ($Name -eq '.') {
        $warning = "Defaulting to member-access operator; for the dot-sourcing operator, pass '. '"
      }
      elseif ($Name -eq '&') {
        $warning = "Defaulting to call operator; for the background operator, pass ' &'"
      }
      elseif ($Name.Trim() -eq '@') {
        $warning = "Defaulting to splatting operator; for the array-subexpression operator, pass '@()'; for here-strings, pass '@`"`"@' or -QuotingRules"
      }
      elseif (-not $entry) {
        # Remove any spaces, to support name variations such as '( )', '[ ]'
        $normalizedName = $Name -replace ' '
      }

      if (-not $entry) {
        # If not, try prepending "-", to allow users to specify 'replace' instead of '-replace', for instance.
        $entry = $opTable["-$normalizedName"]
      }
      if (-not $entry) {
        # Variations of redirection operators.
        if ($entry -match '^[\d*]?>>?(&\d?)') {
          $entry = $opTable['>']
        }
      }
      if (-not $entry) {
        # Map case variants to their unqualified form; e.g. '-ireplace' -> '-replace'
        $baseName = $normalizedName -replace '^(?=-?)[ci](?=[a-z])'
        if ($baseName -ne $normalizedName) {
          if ($baseName -notlike '-*') { $baseName = '-' + $baseName }
          $entry = $opTable[$baseName]
        }
      }
      if (-not $entry -and $normalizedName -like '`[*`]') {
        # varations of referring to the index / cast / type-constraint operator
        $bracketName = $normalizedName
        if ($bracketName -eq '[]') {
          $bracketName = '[0]' # default to indexer, but warn
          $warning = "Defaulting to index operator; for the cast / type-constraint operators, pass '[int]'"
        }
        elseif ($bracketName -match '^\[(\d+|[''"].*[''"])\]$') {
          $bracketName = '[0]' # indexer - numeric or string
        }
        else {
          $bracketName = '[int]' # cast
        }
        $entry = $opTable[$bracketName]
      }

      if (-not $entry) {
        Throw "Not a recognized operator: $Name"
      }
      elseif ($warning) {
        Write-Warning $warning
      }

      $url = "https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/" + $entry.Topic
      if ($entry.Anchor) {
        $url += '#' + $entry.Anchor
      }
      break
    }

    'Precedence' {
      $url = 'https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Operator_Precedence'
      break
    }

    'QuotingRules' {
      $url = 'https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Quoting_Rules'
      break
    }

    'HomePage' {
      $url = 'https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Operators'
      break
    }

    'List' {
      # List the operators table below.
    }

    Default { Throw "What are you doing here?" }
  }

  if ($url -and $Version) {
    $versionQueryString = '?view=powershell-' + $Version
    if ($url.Contains('#')) {
      $url = $url -replace '(#.+)$', ($versionQueryString + '$1')
    }
    else {
      $url += $versionQueryString
    }
  }

  # -WhatIf support.
  if (-not $PSCmdlet.ShouldProcess((("`n" + $url + "`n"), "List all operators")[$parameterSetNameInEffect -eq 'List'])) { return }

  if ($parameterSetNameInEffect -eq 'List') {

    $opTable.Values | Select-Object Name, FriendlyName, Category | Sort-Object Category, Name

  }
  else {

    if ($CopyUrl) {
      Write-Verbose "Copying URL to clipboard: $url"
      Set-Clipboard $url
    }
    else {
      Write-Verbose "Navigating to: $url"
      Start-Process $url
    }

  }
}

Show-TypeHelp源码:

function Show-TypeHelp {
  <#
  .SYNOPSIS
  Shows documentation for built-in .NET types.

  .DESCRIPTION
  Navigates to the specified .NET type's docs.microsoft.com documentation page
  in your default web browser, assuming the type comes with .NET.

  Use -WhatIf to preview the URL that would be opened.

  There are two basic invocation patterns:

  * Provide the full name of a type a type accelerator or a [type] instance
    via the -Type parameter.

     * Tab-completion works with the (prefixes of) a type's simple name (without
      namespace component); e.g., Get-TypeHelp List<tab> cycles through all
      loaded types whose name is or starts with 'List'.

  * Pipe instance(s) of the type of interest.

  .PARAMETER Type
  Can be the name of a type (e.g. "string"), or a type literal (e.g. [string]).
  
  If given a name, the name must be one of the following:
   * The type's full name; e.g., 'System.Xml.XmlDocument'.
   * The full name with the 'System.' prefix omitted; e.g., 'Xml.XmlDocument'
   * The name of a PowerShell type accelerator; e.g., 'xml'

  .PARAMETER Member
  The optional name of a property or method to get specific information on.
  If the target type has no such member, a warning is issued, and you're taken
  to the type's home page.

  .PARAMETER InputObject
  Object(s), typically provided via the pipeline, whose type's documentation
  page should be opened.

  .PARAMETER Platform
  The target .NET platform / standard, which must include a specific major.minor
  version number; e.g., 'dotnetcore-3.1'.
  Currently (v7.0), the latest 'netframework-*' version is targeted by default, i.e.,
  the Windows-only .NET Framework (FullCLR).

  Use tab completion to cycle through the available platforms, but note that
  you must complete the specific version number yourself.

  .EXAMPLE
  Get-TypeHelp xml

  Opens the documentation page for type [xml], i.e., for System.Xml.XmlDocument

  .EXAMPLE
  Get-TypeHelp string split

  Opens the documentation page for the System.String type's Split() method.

  .EXAMPLE
  Get-Item / | Get-TypeHelp

  Opens the documentation page for type System.IO.DirectoryInfo, an instance
  of which is output by the Get-Item command.

  .EXAMPLE
  Get-TypeHelp regex -Platform netcore-3.1

  Opens the documenation page for type System.Text.RegularExpressions.Regex
  for the .NET Core 3.1 platform.
  #>

  [CmdletBinding(DefaultParameterSetName = 'ByType', SupportsShouldProcess = $true)]
  [OutputType()] # No output.
  param(
    [Parameter(ParameterSetName = 'ByType', Mandatory, Position = 0)]
    [ArgumentCompleter( {
        param($cmd, $param, $wordToComplete)
        # Remove enclosing / opening quote(s), if present.
        $wordToComplete = $wordToComplete -replace '^[''"]|[''"]$'
        if ($tp = $wordToComplete -as [Type]) {
          # Already a full type name or the name of a type accelerator such as [xml]
          $tp.FullName
        }
        else {
          # Get the full names of all public types (including nested ones), but exclude dynamic assemblies.
          # (Dynamic assemblies can't be expected to have documentation pages anyway; also, not excluding them would break the .GetExportedTypes() call.)
          $allLoadedTypes = [System.AppDomain]::CurrentDomain.GetAssemblies().Where( { -not $_.IsDynamic }).GetExportedTypes().FullName
          # Prefix-name-only-match against all loaded full type names from non-dynamic assemblies at
          # and enclose in embedded '...' if the type name contains a ` char. (generics), then sort.
          $(foreach ($match in $allLoadedTypes -match "[+.]$wordToComplete[^.]*$") {
              ($match, "'$match'")[$match -match '`']
            }) | Sort-Object
        }
      })]
    [Type] $Type
    ,
    [Parameter(ParameterSetName = 'ByType', Position = 1)]
    [string] $Member
    ,
    [Parameter(ParameterSetName = 'ByInstance', ValueFromPipeline, Mandatory)]
    [ValidateNotNullOrEmpty()]
    $InputObject
    ,
    [ArgumentCompleter( {
        'netcore-', 'netframework-', 'xamarinmac-', 'dotnet-plat-ext-', 'netstandard-', 'dotnet-uwp-', 'xamarinandroid-', 'xamarinios-10.8', 'xamarinmac-' -like "$wordToComplete*"
      })]
    [string] $Platform
    ,
    [Alias('cp')]
    [switch] $CopyUrl
  )
  
  begin {
    $types = [System.Collections.Generic.List[Type]]::new()
    $instances = [System.Collections.Generic.List[object]]::new()
  
    if ($Platform -and $Platform -notmatch '^[a-z][a-z-]+-\d+\.\d+$') {
      Throw "The -Platform value must be in the form '<platform-id>-<major>.<minor>'; e.g., 'netcore-3.1'; use tab completion to cycle through the supported platforms and add a version number."
    }
  }
  process {
    switch ($PSCmdlet.ParameterSetName) {
      'ByType' { $types.Add($Type) }
      'ByInstance' { $instances.Add($InputObject) }
      Default { Throw 'What are you doing here?' }
    }
  }
  end {
  
    # If instances were given, determine their types now.
    if ($PSCmdlet.ParameterSetName -eq 'ByInstance') {
      $types = $instances.ToArray().ForEach('GetType') | Select-Object -Unique
    }

    $urls = foreach ($tp in $types) {
      # Make sure that the member exists, otherwise a 404 happens.
      if ($Member -and $tp.GetMembers().Name -notcontains $Member) {
        Write-Warning "Ignoring member name '$Member', because type '$tp' has no such member."
        $Member = ''
      }
      # Transform the full type name to the format used in the URLs.
      # '`1' -> '-1'
      # System.Environment+SpecialFolder -> 'System.Environment.SpecialFolder'
      $typeNameForUrl = $tp.FullName -replace '`', '-' -replace '\+', '.'
      "https://docs.microsoft.com/$PSCulture/dotnet/api/$typeNameForUrl" + ('', ".$Member")[$Member -ne ''] + ('', "?view=$Platform")[[bool] $Platform]
    }
  
    if ($PSCmdlet.ShouldProcess("`n" + ($urls -join "`n") + "`n")) { 
      if ($CopyUrl) {
        Write-Verbose "Copying URL(s) to clipboard: $urls"
        Set-Clipboard $urls
      }
      else {
        Write-Verbose "Navigating to: $urls"
        Start-Process $urls
      }
    }
  
  }
}

【讨论】:

  • 这是您在这里完成的一项令人难以置信的工作@mklement0,非常感谢。我正在考虑进行类似的工作(查找每个运算符,但我可能永远不会解决它,并且您的版本比我能够开发的版本要好得多)。非常感谢您为这个答案所做的所有这些,我只能希望微软将这样的东西导入核心语言,因为在我看来,易用性非常值得,这确实有助于获取帮助信息。再次感谢,这里非常棒的脚本(!)将进入我的 $profile。 :-)
  • 我很高兴这个答案是有帮助的,我很欣赏良好的反馈,@YorSubs。我实际上在 GitHub 上创建了两个功能请求(请参阅我添加到答案顶部的链接),因此您可以在那里对它们进行投票。我建议您从链接的 Gists 中获取代码,而不是从以下答案中获取代码:我已经在那里进行了更改,并且只会在此处维护代码(您必须将代码包装在 function &lt;name&gt; { ... } 中)。
猜你喜欢
  • 2014-06-11
  • 1970-01-01
  • 2010-12-30
  • 2017-02-07
  • 2015-06-21
  • 2021-10-06
  • 2018-10-04
  • 2019-06-08
  • 1970-01-01
相关资源
最近更新 更多