Javascript 是否使用Windows脚本复制子进程环境? 我试图创建一个简单的Windows登录脚本,运行它来设置我的Visual C++环境。(运行Windows 7 Home Premium)

Javascript 是否使用Windows脚本复制子进程环境? 我试图创建一个简单的Windows登录脚本,运行它来设置我的Visual C++环境。(运行Windows 7 Home Premium),javascript,windows,batch-file,environment-variables,wsh,Javascript,Windows,Batch File,Environment Variables,Wsh,如果在cmd.exe的实例中运行,vcvvarsall.bat为该cmd.exe实例设置环境。但是,我希望在当前用户会话中设置这些环境变量 我想做的是作为登录脚本运行vcvvarsall.bat。但是很明显,单独这样做并不能在我的Windows用户会话中保持环境变量。因此,我确实希望将vcvarsall.bat作为子进程运行,当它终止时,从子进程复制与当前用户环境变量不同的任何环境变量 有没有办法使用Windows脚本访问子进程环境 (使用WScript.Exec(),WScript.Run()

如果在
cmd.exe
的实例中运行,
vcvvarsall.bat
为该
cmd.exe
实例设置环境。但是,我希望在当前用户会话中设置这些环境变量

我想做的是作为登录脚本运行
vcvvarsall.bat
。但是很明显,单独这样做并不能在我的Windows用户会话中保持环境变量。因此,我确实希望将
vcvarsall.bat
作为子进程运行,当它终止时,从子进程复制与当前用户环境变量不同的任何环境变量

有没有办法使用Windows脚本访问子进程环境


(使用
WScript.Exec()
WScript.Run()
WScript.CreateObject(“WSHController”).CreateScript().Execute()
,或任何其他方法??)无法将子环境复制到父环境中。但是,您可以使用
WshShell.Environment
对象以超出
setx
命令功能的方式创建持久化环境变量

不久前,我编写了一个名为
SetEnv.bat
的批处理JScript混合脚本:

@if (@CodeSection == @Batch) @then


:: SetEnv.bat: Creation of persistent environment variables via a JScript subroutine
:: Antonio Perez Ayala

@echo off
setlocal EnableDelayedExpansion

if "%~1" neq "" if "%~1" neq "/?" goto begin
set start=
for /F "delims=:" %%a in ('findstr /N "^</*usage>" "%~F0"') do (
   if not defined start (set start=%%a) else set /A lines=%%a-start-1
)
set line=0
for /F "skip=%start% tokens=1* delims=:" %%a in ('findstr /N "^" "%~F0"') do (
   echo(%%b
   set /A line+=1
   if !line! equ %lines% goto :EOF
)

<usage>
Create persistent environment variables.

SETENV charVar=code strVar:=string ... [/T:envtype]

  charVar    Specifies the name of one-character environment-variable.
  code       Ascii (Unicode) code of the character assigned to charVar;
             any code is valid, excepting zero.

  strVar     Specifies the name of string environment-variable.
  string     String of characters assigned to strVar;
             if contain spaces or special characters, enclose it in quotes.

  /T         Specify the environment type for the variables.
  envtype     SYSTEM    Applies to all users of the computer and is saved
                        between logoffs and restarts in the registry.
              USER      Applies to the user currently logged on to the
                        computer and is saved between logoffs and restarts.
              VOLATILE  Applies to current logon session and is not saved
                        between logoffs and restarts (this is the default).
              PROCESS   Applies to current process and might be passed to
                        child processes.

Examples:

    [call] SetEnv BEL=7 BS=8 TAB=9 CR=13 LF=10
    [call] SetEnv LastLogoff:="%date% @ %time%" /T:USER
</usage>

:begin

rem Define the variables via JScript
Cscript /nologo /E:JScript "%~F0" %*
goto :EOF


@end


// JScript section: SetEnv subprogram

// Define environment variables given in command-line arguments with this format:
//     charVar=code strVar:="string" ... [/T:SYSTEM|USER|VOLATILE|PROCESS]
// Antonio Perez Ayala

// Reference: http://technet.microsoft.com/en-us/library/ee156595.aspx

var envType = WScript.Arguments.Named.Item("T");
if ( envType == undefined ) envType = "VOLATILE";
var WshShell = WScript.CreateObject("WScript.Shell"),
    colEnvVars = WshShell.Environment(envType),
    args = WScript.Arguments.Unnamed, name_Value, equalSignPos;
for ( var i = 0; i < args.Length; i++ ) {
   name_Value = args.Item(i);
   equalSignPos = name_Value.indexOf("=");
   if ( name_Value.charAt(equalSignPos-1) == ":" )
      colEnvVars(name_Value.slice(0,equalSignPos-1)) = name_Value.slice(equalSignPos+1);
   else {
      colEnvVars(name_Value.slice(0,equalSignPos)) = String.fromCharCode(parseInt(name_Value.slice(equalSignPos+1)));
   }
}

下面是一个结合使用
set
命令和WSH/JavaScript的解决方案。我们的想法是让进程运行
vcvarsall.bat
将其环境转储到标准输出(h/t@arx),然后将环境变量复制到“volatile”环境中,即直到用户重新启动为止的环境

var shell = WScript.CreateObject("WScript.Shell")
var session_env = shell.Environment("Volatile")

// Run 'vcvarsall.bat' and then print its environment variables to standard out
// as described here: https://stackoverflow.com/a/21223991/1911388.
var vcvarsall_bat = "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat"
var script = shell.Exec("cmd /C \"" + vcvarsall_bat + "\" && set")
var stdout = script.StdOut

// Read the environment variables from the script's standard output with method
// described here: https://groups.google.com/d/msg/microsoft.public.scripting.wsh/cwg0QudGp4Y/-wunGEk6sw0J.
// For each line that is a valid environment variable assignment of value X, set
// the variable in the user environment to X if-and-only-if it isn't already set
// to X.
do
{
    WScript.Sleep(10)
    while (! stdout.AtEndOfStream)
    {
        var line = stdout.ReadLine()
        var match = /^([^=]+)=(.*)$/.exec(line)
        if (null != match)
        {
            var varname = match[1]
            var varval  = match[2]
            var prevval = session_env(varname)
            if (prevval.toLowerCase() != varval.toLowerCase())
            {
                session_env(varname) = varval
            }
        }
    }
}
while (0 == script.Status && ! stdout.AtEndOfStream)

如上所述,将上述内容设置为我的登录脚本,我可以在登录到Windows时直接从任何shell或Makefile运行
cl.exe
或任何我需要的VC工具。

谢谢@Aacini。这个解决方案的问题是我不想修改vcvarsall.bat,因为我想把它当作微软的黑盒子。对于新版本的VC,我只想在一个地方更改脚本的路径。请参阅我发布的答案,了解我发现的有用之处。您的方法的问题在于,它增加了
Volatile
输入以前不存在的所有变量,这些变量实际上都是变量。也就是说,像
OS
PATH
TEMP
这样的常规变量不属于
Volatile
类型,对吗?请看我以上答案中的编辑…@Aacini,这是个什么问题?一点冗余并不困扰我,在某些情况下,例如
PATH
vcvvarsall.bat
会对其进行修改,因此我希望将其推送到易失性环境中……在这种情况下,您可以通过
setx
命令以这种方式获得更简单的解决方案:
for/F“tokens=1*delims=“%%A in('set')do setx%%A”%b”
HKEY\U CURRENT\U USER
..@Aacini中定义变量的
setx
变量是否在会话中保持?(即,如果我运行
setx
,然后注销,然后运行“为您的帐户编辑环境变量”,它们是否持久存在?@Aacini。凉的这也是我希望避免的(我不希望我的“编辑您帐户的环境变量”对话框被任何东西污染,除了我故意设置的值)。
var shell = WScript.CreateObject("WScript.Shell")
var session_env = shell.Environment("Volatile")

// Run 'vcvarsall.bat' and then print its environment variables to standard out
// as described here: https://stackoverflow.com/a/21223991/1911388.
var vcvarsall_bat = "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat"
var script = shell.Exec("cmd /C \"" + vcvarsall_bat + "\" && set")
var stdout = script.StdOut

// Read the environment variables from the script's standard output with method
// described here: https://groups.google.com/d/msg/microsoft.public.scripting.wsh/cwg0QudGp4Y/-wunGEk6sw0J.
// For each line that is a valid environment variable assignment of value X, set
// the variable in the user environment to X if-and-only-if it isn't already set
// to X.
do
{
    WScript.Sleep(10)
    while (! stdout.AtEndOfStream)
    {
        var line = stdout.ReadLine()
        var match = /^([^=]+)=(.*)$/.exec(line)
        if (null != match)
        {
            var varname = match[1]
            var varval  = match[2]
            var prevval = session_env(varname)
            if (prevval.toLowerCase() != varval.toLowerCase())
            {
                session_env(varname) = varval
            }
        }
    }
}
while (0 == script.Status && ! stdout.AtEndOfStream)