问题描述
我正在运行以下命令,作为测试代码的一部分,试图确定脚本是否正在交互式会话(即使用CLI)中运行,还是从无控制台远程会话(SSH,SCP,FTP)中运行。
因此,当使用[Environment]::GetCommandLineArgs()
时,在 Powershell Core (pwsh.exe
)CLI会话中,我得到: C:\Program Files\PowerShell\6\pwsh.dll
。这是令人惊讶的,因为我本来希望得到的是 pwsh.exe 而不是DLL。
为什么我得到DLL而不是EXE?
发生了什么事?
解决方法
这是一个已知问题,截至.NET 5.0(基于PowerShell Core 7.1的构建)仍未得到解决(在撰写本文时均处于预览状态,但是我不希望这修复,以便及时发布这些版本。
但是,有一个解决方法实际上是 一般首选的:
[System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName
# Shorter,but slower equivalent (works only from PowerShell):
# (Get-Process -Id $PID).MainModule.FileName
[System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName
优于[Environment]::GetCommandLineArgs()[0]
的原因有两个:
-
以前的始终报告了完整路径。
-
至少在.NET Core 3.1之前,后者可以报告临时位置,即对于将自己提取到幕后此类位置的单文件.NET Core可执行文件。 / p>
请注意, .NET 5.0+将具有专用的[Environment]::ProcessPath
属性,它们的性能也会更好-请参见GitHub PR #42768。
如果要获得[Environment]::GetCommandLineArgs()
的修正的版本-即,将实际的可执行文件存储在索引0
中,并提供真实的参数在其余元素中:
# 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
通过cmd.exe
调用PowerShell CLI进行演示:
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