Better PowerShell Help (Part 3)

by May 17, 2021

In the previous tip we shadowed the original Get-Help cmdlet with a custom proxy function. The function checked whether there was online help for the command, and if so, by default opened the rich online help. That improves the help experience in PowerShell tremendously.

However, with a simple adjustment you can take the function a step further: why not also check the other way? If a user uses the -Online parameter but there is no online help then Get-Help throws an ugly exception. Wouldn’t it be better to show the built-in local help instead of throwing an exception?

This also makes the function resilient to adjustments to $PSDefaultParameterValue when users made -Online the default value for Get-Help.

Here is the updated function:

function Get-Help
{
  # clone the original param block taken from Get-Help
  [CmdletBinding(DefaultParameterSetName='AllUsersView', HelpUri='https://go.microsoft.com/fwlink/?LinkID=113316')]
  param(
    [Parameter(Position=0, ValueFromPipelineByPropertyName)]
    [string]
    $Name,

    [Parameter(ParameterSetName='Online', Mandatory)]
    [switch]
    $Online,

    [ValidateSet('Alias','Cmdlet','Provider','General','FAQ','Glossary','HelpFile','ScriptCommand','Function','Filter','ExternalScript','All','DefaultHelp','Workflow','DscResource','Class','Configuration')]
    [string[]]
    $Category,

    [string]
    $Path,

    [string[]]
    $Component,

    [string[]]
    $Functionality,

    [string[]]
    $Role,

    [Parameter(ParameterSetName='DetailedView', Mandatory)]
    [switch]
    $Detailed,

    [Parameter(ParameterSetName='AllUsersView')]
    [switch]
    $Full,

    [Parameter(ParameterSetName='Examples', Mandatory)]
    [switch]
    $Examples,

    [Parameter(ParameterSetName='Parameters', Mandatory)]
    [string]
    $Parameter,

    [Parameter(ParameterSetName='ShowWindow', Mandatory)]
    [switch]
    $ShowWindow
  )

  begin
  {
    # we do the adjustments only when the user has submitted
    # the -Name, -Category, and -Online parameters
    
    if ( (@($PSBoundParameters.Keys) -ne 'Name' -ne 'Category' -ne 'Online').
         Count -eq 0
       )
    {
      # check whether there IS online help available at all
            
      # retrieve the help URI
      $help = Microsoft.PowerShell.Core\Get-Command -Name $Name 
      # reset the parameter -Online based on availability of online help
      $PSBoundParameters['Online']=
      [string]::IsNullOrWhiteSpace($help.HelpUri) -eq $false
    }
    
    # once the parameter adjustment has been processed, call the original
    # Get-Help cmdlet with the parameters found in $PSBoundParameters
    
    # turn the original Get-Help cmdlet into a proxy command receiving the
    # adjusted parameters
    # with a proxy command, you can invoke its begin, process, and end
    # logic separately. That's required to preserve pipeline functionality
    $cmd = Get-Command -Name 'Get-Help' -CommandType Cmdlet
    $proxy = {& $cmd @PSBoundParameters}.
    GetSteppablePipeline($myInvocation.CommandOrigin)
        
    # now, call its default begin, process, and end blocks in the appropriate 
    # script blocks so it integrates in real-time pipelines
    $proxy.Begin($PSCmdlet)
  }
    
  process { $proxy.Process($_) }
    
  end     { $proxy.End() }
    
  # use the original help taken from Get-Help for this function
  <#
      .ForwardHelpTargetName Microsoft.PowerShell.Core\Get-Help
      .ForwardHelpCategory Cmdlet
  #>
}

Once you run the code, your help system now is a lot smarter, regardless of whether you use Get-Help, help, or the common parameter -?

If there is online help available for a command, it displays by default:

 
PS> Get-Help Get-Service

PS> Get-Service -? 

If there is no online help available, it always displays local help (even if you accidentally specified -Online or use $PSDefaultParameterValue to always use -Online):

 
PS> Connect-IscsiTarget -?

PS> Get-Help Connect-IscsiTarget -Online  

And if you specify other parameters, they still continue to work as expected:

 
PS> Get-Help Get-Service -ShowWindow  

Essentially, the adjustment simply embraces the meanwhile readily available rich online help content and shows it whenever it is available.

If you like this function, add it to your profile script so it will be defined whenever you launch PowerShell. The path can be found here: $profile.CurrentUserAllHosts


Twitter This Tip! ReTweet this Tip!