MarkPflug
MarkPflug

Reputation: 29538

How does powershell resolve command names?

I'm trying to figure out how powershell resolves names, but I can't seem to find any information.

Here is the scenario:

There exists an executable:

c:\stuff\log.exe

The path is set so $env:path = 'c:\stuff\'

I have a module loaded that includes a function name "log" and a binary cmdlet aliased as 'log'.

When I type "log" at the command line, how does PowerShell decide whether to execute c:\stuff\log.exe or the function name log, or the cmdlet alieased as log?

From experimentation it seems the resolution order is: Cmdlet Function executable on the path

But I can't find anything that documents this.

Upvotes: 11

Views: 2489

Answers (3)

mklement0
mklement0

Reputation: 439307

To complement the great existing answers:

A simple, pragmatic way of determining what a given command name will execute and if there are other, shadowed commands with the same name:

Get-Command -All <commandName>

All commands with the given name will be listed in descending order of precedence, i.e., the effective command will be listed first.

For instance, Windows PowerShell has a built-in sc alias for the Set-Content cmdlet, which shadows the native sc.exe (service-control) program (unless you invoke it as sc.exe):

PS> Get-Command -All sc

CommandType     Name                                               Version    Source                                                                                                           
-----------     ----                                               -------    ------                                                                                                           
Alias           sc -> Set-Content                                                                                                                                                              
Application     sc.exe                                             10.0.17... C:\WINDOWS\system32\sc.exe                                                                                       

Upvotes: 4

Duncan
Duncan

Reputation: 95712

If you want to find out the order Powershell looks for a command try using the trace-command cmdlet. For example:

PS C:\scripts> trace-command -name CommandDiscovery -command ls -PSHost
DEBUG: CommandDiscovery Information: 0 : Looking up command: ls
DEBUG: CommandDiscovery Information: 0 : Alias found: ls  Get-ChildItem
DEBUG: CommandDiscovery Information: 0 : Cmdlet found: Get-ChildItem  Microsoft.PowerShell.Commands.GetChildItemCommand


    Directory: C:\scripts


Mode                LastWriteTime     Length Name
...

is nice and short, but:

PS> trace-command -name CommandDiscovery -command log -PSHost

on my system produces more than 1,000 lines of output as it searches for a non-existent log command.

The order seems to be basically expand aliases then find functions, cmdlets then search your path for the command, then do it all again with get- prepended.

The language reference is fairly terse on this, but it does say:

3.8 Name lookup It is possible to have commands of different kinds all having the same name.  The order in which name lookup is performed in such a case is alias, function, cmdlet, and external command.

If it mentions that when commands aren't found it tries again with 'get-' prepended I haven't found that bit.

Upvotes: 9

Rynant
Rynant

Reputation: 24343

From help about_Command_Precedence:

If you do not specify a path, Windows PowerShell uses the following
precedence order when it runs commands:
     1. Alias
     2. Function
     3. Cmdlet
     4. Native Windows commands

Also,

When the session contains items of the same type that have the same   
name, such as two cmdlets with the same name, Windows PowerShell      
runs the item that was added to the session most recently.  

Calling commands with the same name

about_Command_Precedence also goes into detail about how to explicitly call commands with the same name.

Here are some ways to call a log command from different sources.

# Add '.exe' for executables
log.exe 'This is my log message.'

# Specify the module name
MyModule\log 'This is my log message.'

# Specify alias vs function
&(gi alias:\log) 'This is my log message.'
&(gi function:\log) 'This is my log message.'

Upvotes: 14

Related Questions