Not Specifying a Verb in PowerShell is an Expensive Shortcut

When working with PowerShell, there are lots of shortcuts that can be taken and while some of them may seem like a good idea at first, they usually end up costing you more trouble than they're worth in the long run.

I recently saw a Tweet that a fellow PowerShell enthusiast Tore Groneng‏ responded to which referenced running commands in PowerShell without specifying a verb. Such as "Service" for Get-Service.

1Service

no-verb1a.jpg

That works great, right? Not so fast. It might appear to be a great shortcut on the surface, but what's occurring under the covers?

I originally got involved with that Tweet because one of the referenced nouns (Process) didn't work by itself.

1Process

no-verb2a.jpg

My guess was that this was due to Process being a reserved word because it's used with Pipeline input as are Begin and End. Mathias Jessen confirmed this and said it's because the parser gets in the way. He also stated that using the call operator with Process works fine.

1& Process

no-verb3a.jpg

If you are going to use a shortcut like this, treat it like an alias and only use it interactively and never in code that you save whether it's in scripts, functions, or modules. This shortcut, however, is much, much worse from a performance standpoint than using the full command name or even its alias.

Be sure to read Jason Shirk's comment to this GitHub issue (Jason is a member of the PowerShell team at Microsoft). Here's the relevant portion of Jason's comment:

"It is also very expensive - we first search normally (including the PATH), and if that fails, we repeat the search prepending Get-. Personally, I'd rather remove this misfeature than formalize it."

You can see the problem that Jason referenced in his comment when viewing the output of the command that Mathias Jessen provided.

1Trace-Command -Expression {Service} -Name CommandDiscovery -PSHost | Out-Null

no-verb4a.jpg

Compare that output to when the full command name is used.

1Trace-Command -Expression {Get-Service} -Name CommandDiscovery -PSHost | Out-Null

no-verb5a.jpg

Using an alias adds one additional step, but is still way more efficient than using just a noun.

1Trace-Command -Expression {gsv} -Name CommandDiscovery -PSHost | Out-Null

no-verb6a.jpg

Brandin Olin responded to one of the original Tweets in the thread with some words of wisdom "I’ll take verbose and explicit over clever and obtuse. Especially if I’m that “other guy” :)" The other guy he was referencing was in response to Tore Groneng‏'s comment "use it only interactively, never in scripts/modules. Think of the other guy and the performance impact :-)".

Saving those few characters of typing cost a lot of time in the long run. It's like taking a shortcut when driving and then getting lost.

If you're not following the PowerShell enthusiasts referenced in this blog article on Twitter, you should be. I definitely recommend reading through the comments to the Tweet referenced in this blog article and I've written this blog article because it will be much easier to locate and reference six months from now.


Update Mathias Jessen provided the following image with his annotations.

According to the about_Command_Precedence help topic, an implied Get- causes 1, 2, 3, 4, and then 1 again.

1Get-Help -Name about_Command_Precedence

no-verb7a.jpg

"Incorrect" in the previous image refers to the fact that Help is a function, not a cmdlet and that it resolves to the Help function so it never has to look for a cmdlet by that name.

Jason Shirk replied stating that 1, 2, and 3 could also be slow with deep call stacks and that there was a lot of room for improvement.

One of the things I didn't originally mention in this blog article is that the cost of not specifying a verb is always expensive, but it could be even worse if you have lots of items in your path since it searches through the path looking for a command by that name and if it finds one, guess what? It didn't run the command you intended.

If the PowerShell team meant for this to be a valid feature, it looks like they would have just added aliases to the cmdlets similarly to how List is an alias for Format-List.

µ