Batch file 为什么';以管理员身份运行';更改(有时)批处理文件';谁的当前目录?

Batch file 为什么';以管理员身份运行';更改(有时)批处理文件';谁的当前目录?,batch-file,process,windows-7,working-directory,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 错误消息是非常自解释的。找不到文件file1.txt 由于文件名不包含绝对路径,

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

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

我以管理员身份运行批处理文件。这发生在Windows 7 64位桌面计算机上

批处理文件:

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

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

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

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

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

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

echo BAT directory is %~dp0
echo Current directory  is %CD%
您可以注意到它们是不同的,最后一个反斜杠的附加方式与否存在细微的差异

因此,有两种方法来解决这个问题

  • 或者更改当前目录以匹配预期目录

    pushd %~dp0
    XCOPY /y "File1.txt" "File2.txt"
    popd
    
  • 或者在命令中指定完整路径

    XCOPY /y "%~dp0File1.txt" "%~dp0File2.txt"
    
    %SystemRoot%\System32\cmd.exe /C "%1" %*
    

  • 使用上下文菜单项启动批处理文件时,哪个目录是当前工作目录取决于当前用户的用户帐户控制(UAC)设置

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

    @echo Current directory is: %CD%
    @pause
    

    已在用户帐户控制设置中选择

    默认-仅当程序试图更改我的计算机时通知我

    • 当我更改Windows设置时不通知我
    Windows使用以管理员身份运行,使用注册表项

    HKEY_CLASSES_ROOT\batfile\shell\runasuser\command
    
    此注册表项不包含用于执行批处理文件的默认字符串。取而代之的是带有CLSID的字符串值
    DelegateExecute
    {ea72d00e-4960-42fa-ba92-7792a7944c1d}

    结果是打开一个对话框窗口,标题为“用户帐户控制”,文本为:

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

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

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

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

    HKEY_CLASSES_ROOT\batfile\shell\runas\command
    
    HKEY_CLASSES_ROOT\batfile\shell\runas\command
    
    即:

    %SystemRoot%\System32\cmd.exe /C "%1" %*
    
    因此,将打开一个控制台窗口,标题为C:\Windows\System32\cmd.exe,其中有两行:

    Current directory is: C:\Windows\System32
    Press any key to continue . . .
    
    点击任意键后,批处理执行完成,从而关闭
    cmd.exe
    ,从而关闭用户会话


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

    不要在任何时候通知我

    • 程序尝试安装软件或对我的计算机进行更改

    • 我更改Windows设置

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

    现在Windows直接使用该命令

    XCOPY /y "%~dp0File1.txt" "%~dp0File2.txt"
    
    %SystemRoot%\System32\cmd.exe /C "%1" %*
    
    根据密钥的默认字符串

    HKEY_CLASSES_ROOT\batfile\shell\runas\command
    
    HKEY_CLASSES_ROOT\batfile\shell\runas\command
    
    在当前用户会话中

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

    Current directory is: C:\Temp
    Press any key to continue . . .
    
    父进程(Windows资源管理器作为桌面)的当前工作目录用于执行批处理文件,因为在这种情况下不需要切换到其他用户会话


    在他的回答中已经发布了两种可能的解决方案,我在这里复制了这两种解决方案,并做了一些小的改进(
    pushd
    ,目录用双引号括起来),并添加了第三种解决方案

  • 使用pushdpopd将当前目录更改为批处理文件的目录:

    pushd "%~dp0"
    %SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
    popd
    
    cd /D "%~dp0"
    %SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
    
    这也适用于UNC路径。在命令提示窗口中运行
    pushd/?
    ,以了解为什么这也适用于UNC路径

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

    %SystemRoot%\System32\xcopy.exe "%~dp0File1.txt" "%~dp0File2.txt" /Y
    
  • 使用cd将工作目录更改为批处理文件的目录:

    pushd "%~dp0"
    %SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
    popd
    
    cd /D "%~dp0"
    %SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
    
    这不适用于UNC路径,因为默认情况下,命令解释器cmd不支持将UNC路径作为当前目录,有关详细信息,请参见示例


  • 为了完整性和模糊性,我添加了另一个解决方案,确认在Windows 8.1下工作,并希望在其他地方工作,因为它依赖于文档化的功能:

    您可以更改
    runas
    命令定义键
    HKEY\u CLASSES\u ROOT\batfile\shell\runas\command

    HKEY\u CLASSES\u ROOT\cmdfile\shell\runas\command
    into

    %SystemRoot%\System32\cmd.exe /S /C "(for %%G in (%1) do cd /D "%%~dpG") & "%1"" %*
    
    当使用
    runas
    动词(分别为“以管理员身份运行”菜单项)启动时,将导致
    bat
    cmd
    文件在其包含目录中启动

    添加到原始命令的操作:

    • cmd/S
      去掉
      /C
    • 对于%%G in(%1)do
      枚举其单个条目,
      %1
      参数, 使其可作为循环体中的
      %%G
      进行扩展;这封信是随意的,但有些可能是“保留的”
    • %%~dpG
      扩展到
      %%G
      d河和p路径,~平铺去除引号(如果存在),这就是为什么我们显式地将它们添加回去
    • cd/D
      更改D驱动器和目录t