3

When I call the following code:

Start-Process Firefox

Then the PowerShell opens the browser. I can do that with several other programs and it works. My question is: How does the PowerShell know which program to open if I type Firefox? I mean, Im not using a concrete Path or something ...

I though it has something to do with the environment variables ... But I cannot find any variable there which is called Firefox ... How can he know?

2 Answers2

5

I traced two halves of it, but I can't make them meet in the middle.

Process Monitor shows it checks the PATHs, and eventually checks HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe so that's my answer to how it finds the install location, and then runs it.

That registry key is for Application Registration which says:

When the ShellExecuteEx function is called with the name of an executable file in its lpFile parameter, there are several places where the function looks for the file. We recommend registering your application in the App Paths registry subkey.

  • The file is sought in the following locations:
  • The current working directory.
  • The Windows directory only (no subdirectories are searched).
  • The Windows\System32 directory.
  • Directories listed in the PATH environment variable.
  • Recommended: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths

That implies PowerShell calls the Windows ShellExecuteEx function, which finds FireFox as a registered application, or it tries the same kind of searching itself internally.


Going the other way to try and confirm that, the Start-Process cmdlet has a parameter set called UseShellExecute. The 'Notes' of that help says:

This cmdlet is implemented by using the Start method of the System.Diagnostics.Process class. For more information about this method, see Process.Start Method

Trying to trace through the source code on GitHub:

Here is the PowerShell source code for Start-Process.

Here, at this line it tries to look up the $FilePath parameter with CommandDiscovery.LookupCommandInfo.

Here it checks else if (ParameterSetName.Equals("UseShellExecute"))

Then Here is the .Start() function which either starts it with ShellExecute or Process.Start()

OK, not sure if ShellExecute and ShellExecuteEx behave the same, but it could be PS calling Windows, which is doing the search for "FireFox".

That CommandSearcher.LookupCommandInfo comes in here and follows to TryNormalSearch() which is implemented here and immediately starts a CommandSearcher which has a state machine for the things it will search

  • SearchState.SearchingAliases
  • Functions
  • CmdLets
  • SearchingBuiltinScripts
  • StartSearchingForExternalCommands
  • PowerShellPathResolution
  • QualifiedFileSystemPath

and there I get lost. I can't follow it any further right now.

  • Either it shortcuts straight to Windows doing the lookup
  • Or the PowerShell CommandSearcher does the same search somehow
  • Or the PowerShell CommandSearcher in some way runs out of searching, and the whole thing falls back to asking Windows search.
    • The fact that Process Monitor only logs one query in each PATH folder for "firefox.*" and then goes to the registry key suggests it's not doing this one, or I'd expect many more lookups.
    • The fact that it logs one query for "get-firefox.*" in each PATH folder suggests it is PowerShell's command searcher doing the lookup and not Windows.

Hmm.

TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87
  • Holy! Thousand Thanks to you! Now I really learned something! Firefox.exe stands in the App_Paths in the registry. Another program I installed on my Computer which was not listed there is found under $env:path. Thank You so much! Have a nice day! –  Nov 03 '16 at 09:10
1

Using Process Monitor I was able to trace the PowerShell. It first searches the $env:path variable, then the $profile variable. In my case firefox wasn't found and then it searches through a whole lot in the Registry and somehow finds it. It might have something to do with how firefox is installed on the system.

Jonas Andersen
  • 489
  • 4
  • 12