gpt4 book ai didi

windows - 在 CMD 批处理文件中,我可以确定它是否是从 powershell 运行的吗?

转载 作者:可可西里 更新时间:2023-11-01 12:43:03 25 4
gpt4 key购买 nike

我有一个 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 调用的,以便我可以向用户显示警告?这需要在没有任何第 3 方实用程序的情况下完成。

最佳答案

Your own answer is robust虽然由于需要运行 PowerShell 进程,它通常很慢,但可以通过优化用于确定调用 shell 的 PowerShell 命令来显着加快速度:

@echo off
setlocal
CALL :GETPARENT PARENT
IF /I "%PARENT%" == "powershell" GOTO :ISPOWERSHELL
IF /I "%PARENT%" == "pwsh" GOTO :ISPOWERSHELL
endlocal

echo Not running from Powershell
SET MyEnvVariable=MyValue

GOTO :EOF

:GETPARENT
SET "PSCMD=$ppid=$pid;while($i++ -lt 3 -and ($ppid=(Get-CimInstance Win32_Process -Filter ('ProcessID='+$ppid)).ParentProcessId)) {}; (Get-Process -EA Ignore -ID $ppid).Name"

for /f "tokens=*" %%i in ('powershell -noprofile -command "%PSCMD%"') do SET %1=%%i

GOTO :EOF

:ISPOWERSHELL
echo. >&2
echo ERROR: This batch file may not be run from a PowerShell prompt >&2
echo. >&2
exit /b 1

在我的机器上,它的运行速度大约快 3 - 4 倍 (YMMV) - 但仍然需要将近 1 秒。

请注意,我还添加了对进程名称 pwsh 的检查,以便使该解决方案也适用于 PowerShell Core


更快的替代方案 - 尽管不够健壮:

下面的解决方案依赖于以下假设,这在默认安装中是正确的:

只有名为 PSModulePath系统 环境变量在注册表中永久定义(不是 用户特定 变量)。

该解决方案依赖于检测 PSModulePath 中是否存在用户特定路径,PowerShell 在启动时会自动添加该路径。

@echo off
echo %PSModulePath% | findstr %USERPROFILE% >NUL
IF %ERRORLEVEL% EQU 0 goto :ISPOWERSHELL

echo Not running from Powershell
SET MyEnvVariable=MyValue

GOTO :EOF

:ISPOWERSHELL
echo. >&2
echo ERROR: This batch file may not be run from a PowerShell prompt >&2
echo. >&2
exit /b 1

按需启动新的 cmd.exe 控制台窗口的替代方法:

基于之前的方法,以下变体只是在检测到正在运行时在新的 cmd.exe 窗口中重新调用批处理文件来自 PowerShell

这不仅对用户来说更方便,还减轻了上述解决方案产生误报的问题:当从从 PowerShell 启动的交互式 cmd.exe session 运行时,上述解决方案将拒绝运行,即使它们应该运行,如 PetSerAl指出。
虽然下面的解决方案本身也没有检测到这种情况,但它仍然会打开一个可用的(尽管是新的)窗口,其中设置了环境变量。

@echo off
REM # Unless already being reinvoked via cmd.exe, see if the batch
REM # file is being run from PowerShell.
IF NOT %1.==_isNew. echo %PSModulePath% | findstr %USERPROFILE% >NUL
REM # If so, RE-INVOKE this batch file in a NEW cmd.exe console WINDOW.
IF NOT %1.==_isNew. IF %ERRORLEVEL% EQU 0 start "With Environment" "%~f0" _isNew & goto :EOF

echo Running from cmd.exe, setting environment variables...

REM # Set environment variables.
SET MyEnvVariable=MyValue

REM # If the batch file had to be reinvoked because it was run from PowerShell,
REM # but you want the user to retain the PowerShell experience,
REM # restart PowerShell now, after definining the env. variables.
IF %1.==_isNew. powershell.exe

GOTO :EOF

设置所有环境变量后,请注意最后一个 IF 语句如何重新调用 PowerShell,但在相同 新窗口中,基于调用的假设用户更喜欢在 PowerShell 中工作。
然后,新的 PowerShell session 将看到新定义的环境变量,但请注意,您需要 两次 连续的 exit 调用来关闭窗口。

关于windows - 在 CMD 批处理文件中,我可以确定它是否是从 powershell 运行的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53447286/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com