Ralf_Reddings
Ralf_Reddings

Reputation: 1533

how to stringify the output from get-help <command name> command?

I am trying to get just the syntax section that get-help outputs as a string, for example get-help get-childItem outputs:

NAME
    Get-ChildItem

SYNOPSIS
    Gets the items and child items in one or more specified locations.

SYNTAX
    Get-ChildItem [[-Filter] <System.String>] [-Attributes {Archive | Compressed | Device | Directory | Encrypted | Hidden | IntegrityStream | Normal | NoScrubData | NotContentIndexed | Offline | ReadOnly | ReparsePoint | SparseFile | System | Temporary}] [-Depth
    <System.UInt32>] [-Directory] [-Exclude <System.String[]>] [-File] [-FollowSymlink] [-Force] [-Hidden] [-Include <System.String[]>] -LiteralPath <System.String[]> [-Name] [-ReadOnly] [-Recurse] [-System] [<CommonParameters>]
....

DESCRIPTION
    The `Get-ChildItem` cmdlet gets the items in one or more specified locations. If the item is a container, it gets the items inside the container, known as child items. You can use the Recurse parameter to get items in all child containers and use the Depth parameter to
....
RELATED LINKS
    Online Version: https://docs.microsoft.com/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7.1&WT.mc_id=ps-gethelp
....

I am interested in the SYNTAX section, I would like to take the output and print it with a simple function. Many times, I don't wish to see all of the help output and want to just specifically see the command syntax, to get an idea for

So I am thinking of writing a simple function called syntax and just do something like syntax get-childItem and it should only output:

Get-ChildItem [[-Filter] <System.String>] [-Attributes {Archive | Compressed | Device | Directory | Encrypted | Hidden | IntegrityStream | Normal | NoScrubData | NotContentIndexed | Offline | ReadOnly | ReparsePoint | SparseFile | System | Temporary}]...

Get-ChildItem [[-Path] <System.String[]>] [[-Filter] <System.String>] [-Attributes {Archive | Compressed | Device | Directory | Encrypted | Hidden | IntegrityStream | Normal | NoScrubData | NotContentIndexed | Offline | ReadOnly | ReparsePoint | SparseFile...

Getting this syntax section has proven to be a headache though, get-help get-childitem|% syntax will print just the syntax notation:

Get-ChildItem [[-Filter] <System.String>] [-Attributes {Archive | Compressed | Device | Directory | Encrypted | Hidden | IntegrityStream | Normal | NoScrubData | NotContentIndexed | Offline....

But one of my own functions will not. get-help compile-autoHotkey|% syntax prints:

syntaxItem
----------
{@{name=Compile-AutoHotkey; CommonParameters=True; parameter=System.Object[]}}

I wrestled with this issue and it just gets worse:

Is there a reliable ways to get this information default commandlets and user defined functions?

PS: I know there are interactive ways to read the help and get syntax notation such as PsReadline, I personally just want the syntax notation

Upvotes: 2

Views: 105

Answers (2)

mklement0
mklement0

Reputation: 439307

Preface:

  • Santiago's answer is effective in Windows PowerShell, but no longer in PowerShell (Core) 7+, because it relies on a bug that has since been fixed:

    • The .Synopsis property should generally not include syntax diagrams, and instead should only report a command's concise description, as reported in the SYNOPSIS section of Get-Help output as well as of the first paragraph following the heading in the online help topics such as Get-ChildItem

    • The only situation in which it does make sense to have .Synopsis report the syntax diagrams is if a given command has no help associated with it at all (in which case no synopsis can be provided) - this is how it works in PowerShell (Core) 7+.

      • However, PowerShell (Core) 7+ has a different bug with respect to trying to make the .syntax and .parameter property values renders as expected for "help-less" commands - see GitHub issue #21125 and the bottom section of this answer.

As a robust, cross-edition alternative to using Get-Help's output, you can use
Get-Command -Syntax <command> to get (just) the syntax diagrams for a given command, which also happens to bypass the aforementioned bugs.

  • Your own attempt - which relies on Get-Help output - would require compensating for these bugs - see the bottom section for an explanation and implementation.

Thus, you could define your syntax function as follows:

function syntax {
  param(
    [Parameter(Mandatory, ValueFromPipeline)]
    [string] $Command,
    # Optional parameter that provides context for discovery of dynamic parameters.
    [object[]] $ArgumentList 

  )
  process {
    $cmdInfo = Get-Command -Name $Command; if (-not $?) { return }
    # Windows PowerShell: Resolve an alias to its target command.
    # PowerShell (Core) does that automatically.
    if (-not $IsCoreCLR -and ($cmdInfo = $cmdInfo.ResolvedCommand)) {
      $Command = $cmdInfo.Name
    }
    Get-Command -Syntax $Command -ArgumentList $ArgumentList
  }
}

Note that the above automatically resolves aliases to their target commands in Windows PowerShell (which PowerShell (Core) 7+ does by default), so that you can call syntax as follows, for instance, relying on built-in alias dir getting resolved to Get-ChildItem:

syntax dir  # -> syntax diagrams for Get-ChildItem
  • Pros:

    • This works even with PowerShell commands that do not come with help.

      • That is, it also works for PowerShell commands that come with neither comment-based nor MAML-based help, provided via separate files.
    • Given that the information is directly derived from the actual commands via reflection, it is guaranteed to report the actual syntax, whereas it is technically possible for MAML-based information to diverge from the actual syntax.

  • Potential con:

    • Get-Command -Syntax takes the current provider context into account with respect to dynamic parameters, whereas the information provided by Get-Help - if MAML-based - may choose to report dynamic parameters across all providers by default, as is the case with (Get-Help Get-ChildItem).syntax

    • To situationally compensate for that, the function above offers an optional -ArgumentList parameter to which you can pass an argument that implies a specific provider context, analogous to Get-Command's own -ArgumentList parameter, to which said argument is relayed.

      • While -ArgumentList only accepts positional arguments, the fact that provider cmdlets bind their first positional argument to the -Path parameter means that passing a single positional argument is sufficient to imply the provider context; e.g. to use the syntax function above to reflect dynamic parameters for the Certificate provider (e.g., -Eku and -ExpiringDays, invoke it as follows, which binds the Cert: drive specification positionally to -ArgumentList):

        syntax Get-ChildItem Cert:
        

As for what you tried:

get-help get-childitem | % syntax

The above:

  • In PowerShell (Core) 7+: Malfunctions (doesn't render the syntax diagrams) for commands that lack any help information, which aren't just custom commands, but - depending on how PowerShell (Core) was installed - can include the built-in cmdlets.

  • In Windows PowerShell: Malfunctions for any command.

What it comes down to is that Get-Help emits [pscustomobject] instances, including for the nested .syntax property, that rely on ETS type names to select suitable output-formatting definitions in order to render the value of the .syntax property

If the required ETS type name to select the desired formatting isn't reflected in the intrinsic pstypenames property, the object contained in the .syntax property uses default formatting, which results in the - unhelpful - representation shown in your question.

For the desired rendering of the .syntax property value to work consistently, its .pstypenames property value must (also) include a MamlCommandHelpInfo#syntax ETS type name, whereas:

  • in Windows PowerShell it invariably only contains ExtendedCmdletHelpInfo#syntax (only)

  • in PowerShell (Core) 7+ it contains ExtendedCmdletHelpInfo#syntax (only) for commands without help.

While this problem is unlikely to be fixed in Windows PowerShell (which will receive critical fixes only), it may get fixed in PowerShell (Core) 7+ - see GitHub issue #21125, which states that the .parameters property is affected too.

The cross-edition implementation of a syntax function based on the .syntax property would therefore have to look like this:

function syntax {
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [string] $Command
    )
    process {
        $syntaxInfo = (Get-Help $Command).syntax
        # Ensure presence of the relevant ETS type name.
        $syntaxInfo.pstypenames.Insert(0, 'MamlCommandHelpInfo#syntax')
        # Now the output should render as expected.
        $syntaxInfo
    }
}

Sample call:

# Declare a function without help, then ask for its syntax.
function Foo { param([int] $Bar) }; syntax Foo

Output (in both PowerShell editions):

foo [[-Bar] <int>] [<CommonParameters>]

As an aside:

  • Note the - unexpected - inclusion of [<CommonParameters>] in the syntax diagram, given that the function is not an advanced one and therefore doesn't support common parameters.
    This problem has been reported in GitHub issue #17312.

Upvotes: 2

Santiago Squarzon
Santiago Squarzon

Reputation: 60563

The syntax string from the Get-Help output is contained in the .Synopsis property, if you want to make a simple function it's as simple as:

function syntax {
    param(
        [Parameter(Mandatory)]
        [string] $Command
    )

    (Get-Help $Command).Synopsis
}

syntax Get-Item

Upvotes: 3

Related Questions