为什么“以管理员身份运行”会更改(有时)批处理文件的当前目录?

时间:2015-07-25 03:04:27

标签: batch-file process windows-7 working-directory

我有一个批处理文件,与我想要xcopy的文件位于同一目录中。但由于某种原因,找不到该文件。

我认为当前目录始终是批处理文件所在的位置。

我以管理员身份运行批处理文件。这种情况发生在Windows 7 64位台式计算机上。

批处理文件:

@ECHO OFF
XCOPY /y "File1.txt" "File2.txt"
PAUSE

错误:

File not found - File1.txt
0 File(s) copied

3 个答案:

答案 0 :(得分:20)

使用上下文菜单项以管理员身份运行启动批处理文件时,当前工作目录是哪个目录取决于当前用户的用户帐户控制(UAC)设置。 / p>

这可以通过以下小批量文件C:\Temp\Test.bat来证明:

@echo Current directory is: %CD%
@pause

用户帐户控制设置

中选择
  

默认 - 仅在程序尝试更改计算机时通知我

     
      
  • 当我更改Windows设置时,请不要通知我
  •   

并使用以管理员身份运行,Windows使用注册表项

HKEY_CLASSES_ROOT\batfile\shell\runasuser\command

此注册表项不包含用于执行批处理文件的默认字符串。相反,字符串值DelegateExecute的CLSID为{ea72d00e-4960-42fa-ba92-7792a7944c1d}

结果是打开一个标题为用户帐户控制和文本

的对话框窗口
  

是否要允许以下程序对此计算机进行更改?

     

程序名称:Windows命令处理器
  已验证的发布者:Microsoft Windows

在用户确认后,Windows会暂时打开一个新的用户会话,就像在命令行RunAs上使用一样。

在这个新的用户会话中,当前工作目录为%SystemRoot%\System32,现在执行Windows注册表中定义的命令,默认字符串为key

HKEY_CLASSES_ROOT\batfile\shell\runas\command

是:

%SystemRoot%\System32\cmd.exe /C "%1" %*

因此打开一个控制台窗口,标题为 C:\ Windows \ System32 \ cmd.exe 和2行:

Current directory is: C:\Windows\System32
Press any key to continue . . .

点击任意键后,批处理执行完成,导致关闭cmd.exe,从而导致关闭用户会话。

但已选择用户帐户控制设置

  

时不要通知我      
      
  • 程序尝试安装软件或对计算机进行更改

  •   
  • 我对Windows设置进行了更改

  •   

行为不同,因为用户已经提升了权限。

现在Windows直接使用命令

%SystemRoot%\System32\cmd.exe /C "%1" %*

根据密钥的默认字符串

HKEY_CLASSES_ROOT\batfile\shell\runas\command

在当前用户会话中。

结果是打开一个标题为 C:\ Windows \ System32 \ cmd.exe 的控制台窗口,但在窗口中显示为:

Current directory is: C:\Temp
Press any key to continue . . .

父进程的当前工作目录(Windows资源管理器作为桌面)用于执行批处理文件,因为在这种情况下不需要切换到其他用户会话。

PA在他的回答中已经发布了2个可能的解决方案,我在这里复制了一个小的改进(pushd目录用双引号)并添加了第三个。

  1. 使用 pushd popd 将当前目录更改为批处理文件目录:

    pushd "%~dp0"
    %SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
    popd
    

    这也适用于UNC路径。在命令提示符窗口pushd /?中运行,以解释为什么这也适用于UNC路径。

  2. 在源和目标规范中使用批处理文件的目录:

    %SystemRoot%\System32\xcopy.exe "%~dp0File1.txt" "%~dp0File2.txt" /Y
    
  3. 使用 cd

    将工作目录更改为批处理文件的目录
    cd /D "%~dp0"
    %SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
    

    这对UNC路径不起作用,因为命令解释程序 cmd 默认情况下不支持将UNC路径作为当前目录,有关详细信息,请参阅示例CMD does not support UNC paths as current directories

答案 1 :(得分:2)

错误消息非常自我解释。找不到文件file1.txt

由于文件名不包含绝对路径,因此系统会尝试在当前目录中找到它。您当前的目录不包含此文件。

您的误解是当前目录不是包含bat文件的目录。这是两个不相关的概念。

您可以通过在bat文件中添加这两个命令轻松检查

echo BAT directory is %~dp0
echo Current directory  is %CD%

您可以注意到它们是不同的,并且最后一个反斜杠的添加方式存在细微差别。

所以,实际上有两种方法可以解决这个问题

  1. 更改当前目录以匹配预期的目录

    pushd %~dp0
    XCOPY /y "File1.txt" "File2.txt"
    popd
    
  2. 或在命令

    中指定完整路径
    XCOPY /y "%~dp0File1.txt" "%~dp0File2.txt"
    

答案 2 :(得分:1)

为了完整性和默默无闻,我添加了另一种解决方法,确认在Windows 8.1下工作并期望在其他地方工作,因为它依赖于记录的功能:

您可以更改runas命令定义键
HKEY_CLASSES_ROOT\batfile\shell\runas\command
HKEY_CLASSES_ROOT\cmdfile\shell\runas\command进入

%SystemRoot%\System32\cmd.exe /S /C "(for %%G in (%1) do cd /D "%%~dpG") & "%1"" %*

当使用bat动词分别以“以管理员身份运行”菜单项启动时,会导致cmdrunas文件从其包含目录开始。

原始命令的添加内容恰好如下:

  • cmd /S/C
  • 之后删除命令字符串中的第一个和最后一个(双)引号
  • for %%G in (%1) do枚举其单个条目%1参数, 使它可以在循环体中以%%G扩展;这封信是任意的,但有些可能是“保留”
  • %%~dpG扩展到%%G d p ath,代替剥离引号如果存在,这就是我们明确添加它们的原因
  • cd /D d 铆钉和目录更改为其参数,最后
  • &运行第二个命令"%1" %*,无论第一个命令是否成功。

可以使用甚至支持UNC路径的pushd,但是迷路popd会将任何脚本放在system32目录中,而不是行为I会喜欢的。

可能会打破很多。

享受击败操作系统的安全机制:)

相关问题