我有一个Windows批处理文件,其目的是设置一些环境变量,例如。
=== MyFile.cmd ===
SET MyEnvVariable=MyValue
字符串
用户可以在执行需要环境变量的工作之前运行此命令,例如:
C:\> MyFile.cmd
C:\> echo "%MyEnvVariable%" <-- outputs "MyValue"
C:\> ... do work that needs the environment variable
型
这大致相当于Visual Studio安装的“开发人员命令提示符”快捷方式,它设置了运行VS实用程序所需的环境变量。
但是,如果用户碰巧打开了Powershell提示符,环境变量当然不会传播回Powershell:
PS C:\> MyFile.cmd
PS C:\> Write-Output "${env:MyEnvVariable}" # Outputs an empty string
型
这可能会让在CMD和PowerShell之间切换的用户感到困惑。
有没有一种方法可以在我的批处理文件MyFile.cmd
中检测到它是从PowerShell调用的,这样我就可以,例如,向用户显示警告?这需要在没有任何第三方实用程序的情况下完成。
4条答案
按热度按时间flmtquvp1#
Your own answer is robust,虽然由于需要运行PowerShell进程而通常较慢,但可以通过优化用于确定调用shell的PowerShell命令来显著加快速度:
字符串
在我的机器上,这运行速度大约快3 - 4倍(YMMV)-但仍然需要几乎1秒钟。
请注意,我还添加了对进程名
pwsh
的检查,以便使解决方案也能与PowerShell Core 一起工作。更快的替代方案-尽管不太稳健:
下面的解决方案依赖于以下假设,默认安装为真:
只有一个名为
PSModulePath
的 system 环境变量被持久地定义在注册表中(也不是一个 * 用户特定的 * 环境变量)。该解决方案依赖于检测
PSModulePath
中是否存在用户特定的路径,PowerShell在启动时会自动添加该路径。型
按需启动新
cmd.exe
控制台窗口的替代方法:在前面的方法的基础上,下面的变体只是在检测到批处理文件正在从PowerShell运行时 * 在新的
cmd.exe
窗口 * 中重新调用批处理文件**。这不仅对用户更方便,而且还减轻了上述解决方案产生假阳性的问题:当从 * 从PowerShell* 启动的交互式
cmd.exe
会话运行时,上述解决方案将拒绝运行,即使它们应该运行,正如PetSerAl所指出的那样。虽然下面的解决方案本身也没有检测到这种情况,但它仍然打开了一个可用的(尽管是新的)窗口,其中设置了环境变量。
型
设置所有环境变量后,请注意最后一个
IF
语句也是如何重新调用PowerShell的,但在 * 相同 * 的新窗口中,基于调用用户更喜欢在PowerShell中工作的假设。然后,新的PowerShell会话将看到新定义的环境变量,但请注意,您需要 * 两个 * 连续的
exit
调用来关闭窗口。3vpjnl9f2#
就像乔·科克常说的:“我靠朋友的一点帮助过日子。”
在这个例子中,来自Lieven Keersmaekers,他的评论使我得到了以下解决方案:
字符串
nmpmafwu3#
我为Chocolatey的RefreshEnv.cmd脚本做了这样的事情:Make refreshenv.bat error if powershell.exe is being used。
由于不相关的原因,我的解决方案最终没有被使用,但它可以在这个repo中使用:beatcracker/detect-batch-subshell。这是它的副本,以防万一。
仅在从交互式命令处理器会话直接调用时运行的脚本
脚本将检测它是否从非交互式会话(
cmd.exe /c detect-batch-subshell.cmd
)运行,并显示相应的错误消息。非交互式shell包括PowerShell/PowerShell伊势、Explorer等。基本上,任何试图通过在单独的
cmd.exe
示例中运行脚本来执行脚本的东西。然而,从PowerShell/PowerShell伊势进入
cmd.exe
会话并在那里执行脚本将起作用。依赖关系
示例:
1.打开
cmd.exe
1.型号
detect-batch-subshell.cmd
输出:
字符串
示例:
1.打开
powershell.exe
1.型号
detect-batch-subshell.cmd
输出:
型
代码
detect-batch-subshell.cmd
个型
ejk8hzay4#
就像beatcracker的答案一样,我认为最好不要对可用于启动批处理脚本的外部shell进行假设,例如,通过bash shell运行批处理文件时也会出现问题。
因为它只使用
CMD
的本机工具,不依赖于任何外部工具或WMI
,所以执行时间非常快。字符串
它检查用于启动
CMD
shell的命令行,以判断脚本是从CMD
内部启动的,还是由外部应用程序使用命令行签名/C script.bat
启动的,/C script.bat
通常由非CMD shell用于启动批处理脚本。如果出于任何原因需要绕过外部启动检测,例如当使用其他命令手动启动脚本以利用定义的变量时,可以通过在
CMD
命令行中将@
前置到脚本的路径来完成:型