[NoBrainer] Help and Get-Help are not the same in PowerShell

This one bit me, when trying to convert the inline help of a PowerShell cmdlet into some markdown enriched code for Github.

For the PowerShell modules and Cmdlet we publish at github we sometimes use the integrated Wiki pages from Github to have some documentation on their use. We often also extract the full inline help and paste it to the wiki page for the respective Cmdlet so people can have a look at it even when they do not have the modules installed. In general this works fine, but a small nuisance is, that the automatic formatting of sections (uppercase) has to be followed by an additional line break, which is not how PowerShell renders the inline help. So why not use PowerShell to help PowerShell with its formatting? A simple and-and-a-half-liner should suffice (which is actually wrapped for better readability), so I thought first:

PARAM (
  $CommandName = 'ConvertTo-Json'
)
$helpFormatted = @();
foreach($line in ((Get-Help $CommandName -Full))) { 
  if( ![string]::IsNullOrWhiteSpace($line) -and $line -ceq $line.ToUpper() ) {
    $line = "{0}`r`n" -f $line; 
  } # if
  $helpFormatted += $line; 
} # foreach
return $helpFormatted;

However, this just brings us the following error message:

PS> $error[0].Exception
Method invocation failed because [MamlCommandHelpInfo#Microsoft.PowerShell.Utility#ConvertTo-Json#FullView] doesn't contain a method named 'ToUpper'.

That was rather strange, because looping over this array must be possible:

PS > $help = help $CommandName -Full;
PS > $help.GetType();
IsPublic IsSerial Name     BaseType
-------- -------- ----     --------
True     True     Object[] System.Array

And why shouldn’t this work, as ‘help’ is an alias to ‘Get-Help’, right? At least calling ‘help’ on ‘help’ pretends that …

PS > help help | Select -First 7

NAME
    Get-Help

SYNOPSIS
    Displays information about Windows PowerShell commands and concepts.

… but actually not really, as it turns out:

PS > $help = Get-Help $CommandName -Full;
PS > $help.GetType();
IsPublic IsSerial Name           BaseType
-------- -------- ----           --------
True     True     PSCustomObject System.Object

So depending on whether we call ‘help’ or ‘Get-Help’ either an array or a PSCustomObject is returned. What happened here? A closer look at the ‘Definition’ of the ‘help’ function reveals that it is more than just an alias, but instead a script that invokes ‘Get-Help’ and returns its output by piping it through ‘more’:

PS > (Get-Command help).Definition

<#
.FORWARDHELPTARGETNAME Get-Help
.FORWARDHELPCATEGORY Cmdlet
#>
[CmdletBinding(DefaultParameterSetName='AllUsersView', HelpUri='http://go.microsoft.com/fwlink/?LinkID=113316')]
param(
  [Parameter(Position=0, ValueFromPipelineByPropertyName=$true)]
  [string]
  ${Name},
  [string]
  ${Path},
  <# some parameters left out for better readability #>
  [Parameter(ParameterSetName='Online', Mandatory=$true)]
  [switch]
  ${Online},
  [Parameter(ParameterSetName='ShowWindow', Mandatory=$true)]
  [switch]
  ${ShowWindow}
  )
    #Set the outputencoding to Console::OutputEncoding. More.com doesn't work well with Unicode.
    $outputEncoding=[System.Console]::OutputEncoding
	Get-Help @PSBoundParameters | more

So, ‘mystery’ solved, but nevertheless strange, as I would expect to behave both ‘functions’ identically …

So coming back to our original problem we can either user ‘help’ or ‘Get-Help | more’ to markup the inline help:

PARAM (
  $CommandName = 'ConvertTo-Json'
)
$helpFormatted = @();
foreach($line in ((help $CommandName -Full))) { 
  if( ![string]::IsNullOrWhiteSpace($line) -and $line -ceq $line.ToUpper() ) {
    $line = "{0}`r`n" -f $line; 
  } # if
  $helpFormatted += $line; 
} # foreach
return $helpFormatted;
# You can then use 'Out-GridView' to display the results:
# $helpFormatted | Out-GridView

See https://github.com/dfch/biz.dfch.PS.System.Utilities/blob/master/ConvertFrom-CmdletHelp.ps1 at biz.dfch.PS.System.Utilities for a full version of the Cmdlet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: