使用Windows脚本复制子进程环境?

时间:2014-03-31 01:01:09

标签: javascript windows batch-file environment-variables wsh

我正在尝试创建一个运行vcvarsall.bat batch file的简单Windows登录脚本来设置我的Visual C ++环境。 (运行Windows 7 Home Premium)。

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

我想要做的是将vcvarsall.bat作为登录脚本运行。但显然单独执行此操作不会在整个Windows用户会话中保留环境变量。所以我真的想将vcvarsall.bat作为子进程运行,当它终止时,复制子进程中与当前USER环境变量不同的任何环境变量。

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

(使用WScript.Exec()WScript.Run()WScript.CreateObject("WSHController").CreateScript().Execute()或任何其他方法???)

2 个答案:

答案 0 :(得分:0)

无法将子环境复制到父环境中。但是,您可以使用WshShell.Environment对象以超出setx命令功能的方式创建持久性环境变量。

前段时间我写了一个名为SetEnv.bat的Batch-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)));
   }
}

这样,您只需修改vcvarsall.bat并将set varname=value命令替换为等效的call SetEnv varname:="value"命令;只需注意需要在字符串变量中使用冒号相等的SetEnv语法。

编辑作为回复评论的新方法

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


@echo off
setlocal EnableDelayedExpansion

rem Get the list of current environment variables
set "v="
for /F "delims==" %%a in ('set') do set v[%%a]=def

rem Call vcvarsall.bat to create new variables
call "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat"

rem Create a file with just the newly created variables and values
(for /F "tokens=1* delims==" %%a in ('set') do (
   set "v=%%a"
   if "!v:~0,2!" neq "v[" if not defined v[%%a] echo %%a=%%b
)) > vcvars.txt

rem Call JScript code to define persistent variables
Cscript /nologo /E:JScript "%~F0" < vcvars.txt
del vcvars.txt
goto :EOF


@end


var WshShell = WScript.CreateObject("WScript.Shell"),
    colEnvVars = WshShell.Environment("Volatile");
while ( ! WScript.Stdin.AtEndOfStream ) {
   var line = WScript.Stdin.ReadLine();
   var pos = line.indexOf("=");
   colEnvVars(line.slice(0,pos)) = line.slice(pos+1);
}

答案 1 :(得分:0)

以下是使用set命令和WSH / JavaScript组合的解决方案。我们的想法是让进程vcvarsall.bat将其环境转储到标准输出(h / t @arx here),然后将环境变量复制到&#34; volatile&#34;环境 - 即持续到用户重新启动的环境。

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)

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