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?
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 6.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