windowspowershellpowershell-core

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


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?


Solution

  • 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:

    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