Почему "Запуск от имени администратора" изменяет (иногда) текущий каталог пакетного файла?

У меня есть командный файл, который находится в том же каталоге, что и файл, который я хочу xcopy, Но по какой-то причине файл не найден.

Я думал, что в текущем каталоге всегда находился командный файл.

Я запускаю командный файл от имени администратора. Это происходит на 64-разрядном настольном компьютере под управлением Windows 7.

Пакетный файл:

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

Ошибка:

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

3 ответа

Решение

Какой каталог является текущим рабочим каталогом при запуске пакетного файла с помощью пункта контекстного меню Запуск от имени администратора, зависит от настройки контроля учетных записей (UAC) для текущего пользователя.

Это можно продемонстрировать с помощью следующего небольшого командного файла 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 со строкой ключа по умолчанию

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 использует непосредственно команду

%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 Explorer в качестве рабочего стола) используется для выполнения командного файла, поскольку в этом случае переключение на другой пользовательский сеанс не требовалось.


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 не поддерживает пути UNC в качестве текущих каталогов для получения подробной информации.

Для полноты и неясности я добавлю еще один обходной путь, подтвержденный как работающий под 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 или же cmd файл, начинающийся в директории, в которой он находится runas Глагол, соответственно пункт меню "Запуск от имени администратора".

Что именно делают дополнения к оригинальной команде:

  • cmd /S удаляет первую и последнюю (двойную) кавычку в командной строке после /C
  • for %%G in (%1) do перечисляет свою единственную запись, %1 аргумент, делая его доступным для расширения как %%G в теле петли; письмо произвольное, но некоторые могут быть "зарезервированы"
  • %%~dpG расширяется в сторону %%G, тильда убирает кавычки, если они есть, поэтому мы добавляем их явно
  • cd /D изменяет и каталог, и каталог на свой аргумент, и, наконец,
  • & запускает вторую команду "%1" %* независимо от успеха первого.

Вы можете использовать pushd который будет даже поддерживать пути UNC, но заблудился popd посадит любой сценарий в system32 каталог, а не поведение, которое я хотел бы.

Это должно быть возможно сделать для exefile вход, но, честно говоря, я бы предпочел жить с несогласованностью, чем пытаться сделать это в моей системе, так как любая ошибка может много сломаться.

Наслаждайтесь победой над механикой безопасности вашей операционной системы:)

Сообщение об ошибке самоочевидно. Файл 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"
    
Другие вопросы по тегам