=== MyFile.cmd === SET MyEnvVariable=MyValue
用户可以在完成需要环境变量的工作之前运行它,例如:
C:\> MyFile.cmd C:\> echo "%MyEnvVariable%" <-- outputs "MyValue" C:\> ... do work that needs the environment variable
这大致相当于Visual Studio安装的“Developer命令提示符”快捷方式,它设置了运行VS实用程序所需的环境变量.
但是,如果用户碰巧打开了Powershell提示符,则环境变量当然不会传播回Powershell:
PS C:\> MyFile.cmd PS C:\> Write-Output "${env:MyEnvVariable}" # Outputs an empty string
对于在CMD和PowerShell之间切换的用户而言,这可能会造成混淆.
有没有办法可以在我的批处理文件MyFile.cmd中检测到它是从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控制台窗口的替代方法:
在以前的方法的基础上,以下变体只是在检测到它是从PowerShell运行时,在新的cmd.exe窗口中重新调用批处理文件.
这不仅对用户来说更方便,还可以缓解上述解决方案产生误报的问题:从PowerShell启动的交互式cmd.exe会话运行时,上述解决方案将拒绝运行,即使它们应该,正如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会话将看到新定义的环境变量,但请注意,您需要两次连续的退出调用才能关闭窗口.