Skip to main content

Get-Help vs Help - the paging/pager inconsistency

When I'm teaching PowerShell to folks, I often like to use the full name of the cmdlets - get-help instead of 'help', get-childitem instead of 'dir'. You get the idea.

I do this to help drive home the verb-noun syntax and because I can't necessarily expect everyone to know the shortcuts that I tend to use.

Well, the problem that I'm about to describe hasn't come up too much - but its annoying and I finally decided to take a minute and figure out what's going on.

The Problem (Powershell 2.0 or 3.0)

In powershell, if I issue the command:

get-help <cmdlet> -full

then I get a wall of text that is not paged (where paging is that "-- More  --" at the bottom of the screen that allows me to read a page at a time.

To be honest, I'd never really spent more than a second thinking about this annoyance because it seemed so trivial, but since I'm in the midst of putting together a curriculum for a powershell class, it got a little more important.

I had basically made the assumption that help (and man) were simply aliases to get-help. This assumption was wrong.  Have a look:


PS C:\> get-alias -Definition get-help
Get-Alias : This command cannot find a matching alias because alias with definition 'get-help' do n
ot exist.
At line:1 char:10
+ get-alias <<<<  -Definition get-help
    + CategoryInfo          : ObjectNotFound: (get-help:String) [Get-Alias], ItemNotFoundException
    + FullyQualifiedErrorId : ItemNotFoundException,Microsoft.PowerShell.Commands.GetAliasCommand

PS C:\>

That's surprising, no aliases at all for get-help? That makes me wonder what "man" is aliased to. Well as it turns out, "man" is pointing to "help".

PS C:\> get-alias man

CommandType     Name                                      Definition
-----------     ----                                      ----------
Alias           man                                       help

Alright, so what is "help" if it isn't an alias but does the exact same thing as get-help? And what's the deal with "man" aliasing to it?! Let's find out.

PS C:\> Get-Command help

CommandType     Name                                      Definition
-----------     ----                                      ----------
Function        help                                      ...

Ah ha! As we can see (highlighted for dramatic effect) - "help" is not an alias. It is a function! Let's have a look at this function.

PS C:\> cd function:
PS Function:\> dir help

CommandType     Name                                      Definition
-----------     ----                                      ----------
Function        help                                      ...


PS Function:\> Get-Content help

<#
.FORWARDHELPTARGETNAME Get-Help
.FORWARDHELPCATEGORY Cmdlet
#>
[CmdletBinding(DefaultParameterSetName='AllUsersView')]
param(
    [Parameter(Position=0, ValueFromPipelineByPropertyName=$true)]
    [System.String]
    ${Name},

    [System.String]
    ${Path},

    [System.String[]]
    ${Category},

    [System.String[]]
    ${Component},

    [System.String[]]
    ${Functionality},

    [System.String[]]
    ${Role},

    [Parameter(ParameterSetName='DetailedView')]
    [Switch]
    ${Detailed},

    [Parameter(ParameterSetName='AllUsersView')]
    [Switch]
    ${Full},

    [Parameter(ParameterSetName='Examples')]
    [Switch]
    ${Examples},

    [Parameter(ParameterSetName='Parameters')]
    [System.String]
    ${Parameter},

    [Switch]
    ${Online})
$outputEncoding=[System.Console]::OutputEncoding

      Get-Help @PSBoundParameters | more

PS Function:\>

And there we have it! The function (again, highlighted for dramatic effect) simply runs the get-help cmdlet put pipes the output to the "more" command. 

Well - that explains the different behavior, and that's good to know.

Interestingly - the "more" command is also simply a function. Output below for the sake of completeness:

PS Function:\> type more
param([string[]]$paths)
$OutputEncoding = [System.Console]::OutputEncoding

if($paths)
{
    foreach ($file in $paths)
    {
        Get-Content $file | more.com
    }
}
else
{
    $input | more.com
}

Interesting stuff.  I hope if any of you guys wondered about this, you now have the answer and can sleep better at night. :)

Comments

Popular posts from this blog

Automating IP addresses with TMG

In the past few months I've had the "opportunity" (note the quotes, maybe I'll write a post about all the troubles I've run into) to deal with some Office 365 integration projects.

When integrating one or more cloud services with Office 365 or Office 365 with on-prem Exchange, it is typical to limit the IP addresses that are aloud to communicate between services. This is an important layer on the security model and obviously reduces the attack surface. Microsoft maintains lists of IP addresses for the various services here:

http://onlinehelp.microsoft.com/en-us/office365-enterprises/hh373144.aspx

That page links to other pages with more specific information about various other Microsoft cloud services such as the link below for Exchange online.

http://help.outlook.com/en-us/140/gg263350.aspx for example.

At the time of this writing, you'll notice that the lists are inconsistent between pages. >:-(

Microsoft on two separate Premier Support Calls has told me…

Windows Last Logon problem and solution

As someone who has been involved in Network Administration (in Microsoft Land) since Windows NT 4.0, I find it surprising that is still so difficult to get simple (yet important) information such as "When was the last time Joe User logged in?".

One would think that, with the fourth edition of Active Directory in production (Windows Server 2008 R2), a tool or set of tools would have been issued with Windows to provide those answers.  Well, because they don't, I've decided to go ahead and write one.  (Yes, I know that there are probably others out there to be downloaded or purchased but... you know, I don't care.)

All that is required: PowerShell 2.0 (and a functioning Active Directory).

Defining the Problem:
Active Directory stores numerous properties on objects in the Directory. Some of these properties are replicated amongst the Domain Controllers and some are not. Unfortunately, for some reason, one of the design decisions was to not replicate the "LastLogo…

LDAP and SAN Certificates

Hey everyone - I ran across an interesting problem with certificates and services. The problem was that I needed to see which certificate is being presented to the client on a non-HTTPS service; specifically - binding to LDAP over SSL (LDAPS). So the question is, how can you be sure what certificate is being presented?

Windows, so far as I've been able to find, does not offer any native help in this regard. Luckily there is a solution, but first let me give you a slightly longer description of the scenario so you can appreciate what we're talking about a little bit better.

An environment exists with some number of Domain Controllers, let's say ten. Within this environment, third party applications (think Java apps, Linux systems, etc) need to bind to LDAP to enumerate groups or validate authentication or whatever. These systems, however, can only have a single (or at best, two) LDAP hosts configured. What do you do? Pick two DCs? Round-Robin DNS?

Well, in my case, a load-b…