启动新的cmd.exe而不是继承环境?

时间:2011-11-24 18:14:09

标签: batch-file cmd

如果我从现有shell启动新的CMD shell,则新shell将继承现有环境。有没有办法启动一个新的shell但是它初始化为系统默认值而不是继承?

目前的结果:

B:\>set _test=blooharky

B:\>cmd
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

B:\>set _
_test=blooharky

期望的结果:

B:\>set _test=blooharky

B:\>cmd /env=default
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

B:\>set _
Environment variable _ not defined

[更新] 此问题的解决方案为start /i cmd,由dbenham below共享。但是,在当前shell已经是第二代的情况下它没有帮助。例如:

d:\>set _
Environment variable _ not defined

d:\>set _test=blooharky

d:\>cmd /k

:: some work done using _test here...
:: ...but after we need a new clean shell:

d:\>start /i cmd

d:\>set _
_test=blooharky

:: uhoh, our shell isn't clean!

6 个答案:

答案 0 :(得分:14)

安德斯的食谱对新环境有详细的控制,由于深度控制,我将其作为公认的答案。然而,该答案中的一个短语导致了我实际用于促进此查询的特定问题的方法。 “环境,它等于初始explorer.exe环境”。哦!我知道怎么做

start /i "%windir%\explorer.exe" "%windir%\system32\cmd.exe"

注意:最初这只是start /i explorer ...,但事实证明它不能可靠地工作,并且应该为两个部分使用完整路径。如果你需要的只是一个解决方案,你现在拥有一切,可以忽略其余的一切。


根据Ander的评论,我在4台Win7计算机上测试了安全警告,包括Pro,Home和Enterprise,32和64bit。我摆弄着用户帐户控制,一路向上,一路向下。还使用非管理员命令提示符shell进行了测试。这些都没有错误或警告。

在Server 2003上,以本地管理员身份登录,我得到一个弹出对话框“文件下载 - 安全警告:你想运行或保存这个文件吗?”带有按钮,用于运行,保存,并取消。按[run]会生成另一个对话框,“Windows资源管理器 - 安全警告:无法验证发布者。确定要运行此软件吗?”。再次按[run]最终会生成一个可用的命令shell。显然有一些奇怪的逻辑导致Internet Explorer被替换为Windows资源管理器而没有exe的完整路径。

它甚至更奇怪:使用带有标题的start(某些建议always include a title)会导致安全警告,无论完整路径如何。其他参数如启动目录似乎没问题。

:: security warning
start "clean shell" /i "%windir%\explorer.exe" "%windir%\system32\cmd.exe"

:: is okay
start /i  /d x:\ "%windir%\explorer.exe" "%windir%\system32\cmd.exe"

答案 1 :(得分:4)

某些变量在登录时初始化,并且不与其他注册表项一起存储,因此如果您想要一个与初始explorer.exe环境相同的环境,则需要将这些项目列入白名单,并希望它们不是被任何人改变:

@echo off
setlocal ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
goto main

:SetFromReg
FOR /F "tokens=2,*" %%A IN ('REG query "%~1" /v "%~2"^|find /I "REG_"') DO (
    call set %~3=%%B
)
goto :EOF

:GetRegEnv
FOR /F %%A IN ('REG query "%~1" /s^|find /I "REG_"') DO (
    if /I not "%%~A"=="Path" call :SetFromReg "%~1" "%%~A" "%%~A"
)
goto :EOF

:InheritOrDelete
for %%A in (save_TEMP Path SystemRoot SystemDrive ProgramFiles CommonProgramFiles ALLUSERSPROFILE COMPUTERNAME LOGONSERVER USERNAME USERDOMAIN HOMEDRIVE HOMEPATH USERPROFILE APPDATA) do if /I "%%~A"=="%~1" goto :EOF
set %~1=
goto :EOF

:main
REM Save temp
set save_TEMP=%temp%
if not defined save_TEMP set save_TEMP=%tmp%

for /F "delims==" %%A in ('set') do call :InheritOrDelete "%%~A"
call :GetRegEnv "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
call :GetRegEnv "HKCU\Environment"

REM Special handling for Path
call :SetFromReg "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" Path Path
setlocal
set u=
call :SetFromReg "HKCU\Environment" Path u
endlocal&if not "%Path%"=="" if not "%u%"=="" set Path=%Path%;%u%

REM Restore TEMP/TMP
set TEMP=%save_TEMP%
set save_TEMP=
set TMP=%TEMP%

REM start some command...
start cmd /d /k set

reg.exe的输出在每个Windows版本上都不一样,所以你必须确保它在目标系统上运行(如果变量的名称包含空格也会有问题,你可以修复通过将"tokens=2,*"替换为"tokens=2,* delims= "(delims equals tab),但在此之前确保reg.exe输出始终使用tab作为分隔符)

您可以使用Windows脚本主机脚本而不是批处理文件解决这些问题:

'orgenvshell.vbs:
Set WShl = CreateObject( "WScript.Shell" )
Set FSO = CreateObject("Scripting.FileSystemObject")

Function CanInherit(n)
    CanInherit = False
    w = Split("SystemRoot SystemDrive ProgramFiles CommonProgramFiles ALLUSERSPROFILE COMPUTERNAME LOGONSERVER USERNAME USERDOMAIN HOMEDRIVE HOMEPATH USERPROFILE APPDATA")
    For Each i In w
        If 0 = StrComp(i,n,1) Then
            CanInherit = True
            Exit Function
        End If
    Next
End Function

Function GetShortFolderPath(p)
    GetShortFolderPath = p
    On Error Resume Next
    GetShortFolderPath = FSO.GetFolder(p).ShortPath
End Function

Sub E(dst,src)
    set envs = WShl.Environment(src)
    For Each i In envs
        t = Split(i,"=")
        n = t(0)
        If n = "" Then n = "="&t(1)
        If IsNull(dst) Then
            If not CanInherit(n) Then envs.Remove n
        Else
            v = Mid(i,Len(n)+2)
            envd = dst
            If "X" = dst Then
                v = WShl.ExpandEnvironmentStrings(v)
                envd = src
                If 0 = StrComp(n,"TMP",1) Then v = GetShortFolderPath(v)
                If 0 = StrComp(n,"TEMP",1) Then v = GetShortFolderPath(v)
            End If
            WShl.Environment(envd)(n) = v
        End If
    Next
End Sub

E Null,"PROCESS"
E "PROCESS","SYSTEM"
E "PROCESS","USER"
E "X","PROCESS"

'Special hack for Path
s = WShl.Environment("SYSTEM")("Path")
u = WShl.Environment("USER")("Path")
If Len(u) Then s = s&";"&u
WShl.Environment("PROCESS")("Path") = WShl.ExpandEnvironmentStrings(s)

'Test a command
WShl.Run "cmd /d /k set ",1

您可以通过查询WMI并使用其他WSH方法删除大量列入白名单的项目......

答案 2 :(得分:4)

如果您愿意使用PowerShell,可以使用:

Start-Process -UseNewEnvironment powershell

Start-Process -UseNewEnvironment cmd

答案 3 :(得分:3)

我不知道在同一个窗口中执行此操作的方法。但是您可以使用

在单独的窗口中完成任务
start /i cmd

如果您希望当前的cmd会话等到新会话结束,则可以添加/wait选项

修改

由于Romário的评论,我的立场得到了纠正。您可以添加/B and /WAIT选项以在同一窗口中创建新的cmd.exe会话。

start /i /b /wait cmd

请注意,新的cmd.exe会继承启动父级时存在的初始环境。如果父项本身是从另一个cmd.exe环境启动的,则它可能不是默认环境。

答案 4 :(得分:0)

下面是我如何为我工作的示例。

@ECHO OFF
TITLE Test
SET SELF=%~dp0%~n0%~x0

ECHO SetVar : %VAR1%
PAUSE
SETX VAR1 "Random Value"
WMIC PROCESS CALL CREATE "%SELF%"
EXIT 0

答案 5 :(得分:-1)

这看起来像一个旧帖子,但这是我尝试过的:

开始/我

此链接有更多信息: http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/start.mspx?mfr=true

该命令应该打开一个新窗口,就像启动cmd环境一样。