Почему "Запуск от имени администратора" изменяет (иногда) текущий каталог пакетного файла?
У меня есть командный файл, который находится в том же каталоге, что и файл, который я хочу 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
с каталогом в двойных кавычках) и с добавлением третьего.
Измените текущий каталог на каталог командного файла, используя pushd и popd:
pushd "%~dp0" %SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y popd
Это работает также для путей UNC. Запустить в окне командной строки
pushd /?
для объяснения, почему это также работает для путей UNC.Используйте каталог командного файла в спецификации источника и назначения:
%SystemRoot%\System32\xcopy.exe "%~dp0File1.txt" "%~dp0File2.txt" /Y
Измените рабочий каталог на каталог командного файла, используя 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%
Вы можете заметить, что они разные, и что есть небольшая разница в том, как добавляется последний обратный слеш или нет.
Таким образом, есть два способа справиться с этой проблемой.
либо измените текущий каталог, чтобы он соответствовал ожидаемому
pushd %~dp0 XCOPY /y "File1.txt" "File2.txt" popd
или укажите полный путь в команде
XCOPY /y "%~dp0File1.txt" "%~dp0File2.txt"