如前所述,.NET 类型的方法System.String.Split()
不是PowerShell的一部分,而是构建 PowerShell 的 .NET 框架的一部分,因此您必须查阅https://docs.microsoft.com上的官方文档.
也就是说,鉴于 PowerShell 和 .NET 之间的紧密集成,如果能够从 PowerShell 中轻松查阅此文档,那就太好了 - 请参阅此 GitHub 建议。
但是,诸如PowerShell 语言功能之类的运算符,既要完全发现它们的文档,又要获得集中的、特定于运算符的信息,目前都很麻烦-split
。
目前没有直接的方法来获取给定操作员的重点信息,但应该有:请参阅此 GitHub 建议。
下面是两个帮助函数,它们试图克服当前的限制(从 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
}
}
}
}