Why does GetCommandLineArgs return a DLL when running pwsh.exe?

517 Views Asked by At

I am running the following command as part of a test code trying to determine if a script is running in an interactive session (i.e. with a CLI) or if from a console-less remote session (SSH,SCP,FTP).

So when using [Environment]::GetCommandLineArgs(), in a Powershell Core (pwsh.exe) CLI session, I get: C:\Program Files\PowerShell\6\pwsh.dll. This is surprising as I would have expected to get pwsh.exe and not a DLL.

Why do I get the DLL and not the EXE?
What is going on?

1

There are 1 best solutions below

0
On BEST ANSWER

This is a known problem that is still not fixed as of .NET 5.0, which PowerShell Core 7.1 is built on (both are in preview as of this writing, but I don't expect a fix to come in time for these releases).

See GitHub issue #11305.

However, there is a workaround that is actually generally preferable:

[System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName

# Shorter, but slower equivalent (works only from PowerShell):
#  (Get-Process -Id $PID).MainModule.FileName

The reason that [System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName is preferable to [Environment]::GetCommandLineArgs()[0] is twofold:

  • The former always reports a full path.

  • At least up to .NET Core 3.1, the latter can report a temporary location, namely for single-file .NET Core executables that extract themselves to such locations behind the scenes.

Note that .NET 5.0+ will have a dedicated [Environment]::ProcessPath property that will also perform better - see GitHub PR #42768.


If you want to get a corrected version of [Environment]::GetCommandLineArgs() - that is, with the real executable stored at index 0 and the true arguments in the remaining elements:

# Get the original array...
# Note: Modifying the array directly works, but you can enclose 
#       the call in @(...) in order to create a *copy* of it.
$cmdLineArgs = [Environment]::GetCommandLineArgs()
# ... and fix the entry for the executable (index 0)
$cmdLineArgs[0] = [Diagnostics.Process]::GetCurrentProcess().MainModule.FileName

To demonstrate with an invocation of the PowerShell CLI from cmd.exe:

C:>pwsh -noprofile -c "$a=[Environment]::GetCommandLineArgs(); $a[0]=[Diagnostics.Process]::GetCurrentProcess().MainModule.FileName; $a"
C:\Program Files\PowerShell\6\pwsh.exe
-noprofile
-c
$a=[Environment]::GetCommandLineArgs(); $a[0]=[Diagnostics.Process]::GetCurrentProcess().MainModule.FileName; $a