J'ai un fichier batch qui se trouve dans le même répertoire que le fichier que je veux xcopy
. Mais pour une raison quelconque, le fichier n'est pas trouvé.
Je pensais que le répertoire actuel était toujours là où se trouvait le fichier de commandes.
J'exécute le fichier de commandes en tant qu'administrateur. Cela se produit sur un ordinateur de bureau Windows 7 64 bits.
Fichier batch:
@ECHO OFF
XCOPY /y "File1.txt" "File2.txt"
PAUSE
Erreur:
File not found - File1.txt
0 File(s) copied
Quel répertoire est le répertoire de travail actuel lors du démarrage d'un fichier de commandes avec l'élément de menu contextuel Exécuter en tant qu'administrateur dépend de Contrôle de compte d'utilisateur (UAC) pour l'utilisateur actuel.
Cela peut être démontré avec le petit fichier de commandes suivant C:\Temp\Test.bat
:
@echo Current directory is: %CD%
@pause
Après avoir sélectionné dans Paramètres de contrôle de compte d'utilisateur
Par défaut - M'avertir uniquement lorsque des programmes tentent d'apporter des modifications à mon ordinateur
- Ne me prévenez pas lorsque je modifie les paramètres de Windows
et en utilisant Exécuter en tant qu'administrateur , Windows utilise la clé de registre
HKEY_CLASSES_ROOT\batfile\Shell\runasuser\command
Cette clé de Registre ne contient pas de chaîne par défaut pour exécuter le fichier de commandes. Au lieu de cela, il y a la valeur de chaîne DelegateExecute
avec le CLSID {ea72d00e-4960-42fa-ba92-7792a7944c1d}
.
Le résultat ouvre une fenêtre de dialogue avec le titre Contrôle de compte d'utilisateur et le texte:
Voulez-vous autoriser le programme suivant à apporter des modifications à cet ordinateur?
Nom du programme: Processeur de commandes Windows
Éditeur vérifié: Microsoft Windows
Après confirmation par l'utilisateur, Windows ouvre temporairement une nouvelle session utilisateur comme lors de l'utilisation en ligne de commande RunAs .
Dans cette nouvelle session utilisateur, le répertoire de travail actuel est %SystemRoot%\System32
en exécutant maintenant la commande définie dans le registre Windows avec la chaîne de clé par défaut
HKEY_CLASSES_ROOT\batfile\Shell\runas\command
lequel est:
%SystemRoot%\System32\cmd.exe /C "%1" %*
Par conséquent, une fenêtre de console est ouverte avec le titre C:\Windows\System32\cmd.exe et les 2 lignes:
Current directory is: C:\Windows\System32
Press any key to continue . . .
Après avoir appuyé sur une touche, l'exécution par lots se termine, ce qui entraîne la fermeture de cmd.exe
ce qui entraîne la fermeture de la session utilisateur.
Mais après avoir sélectionné dans Paramètres de contrôle de compte d'utilisateur
Ne m'informez jamais quand
Les programmes essaient d'installer des logiciels ou d'apporter des modifications à mon ordinateur
Je modifie les paramètres de Windows
le comportement est différent car l'utilisateur a déjà des privilèges élevés.
Maintenant, Windows utilise directement la commande
%SystemRoot%\System32\cmd.exe /C "%1" %*
selon la chaîne de clé par défaut
HKEY_CLASSES_ROOT\batfile\Shell\runas\command
dans la session utilisateur en cours.
Le résultat ouvre une fenêtre de console également avec le titre C:\Windows\System32\cmd.exe , mais affiché dans la fenêtre est:
Current directory is: C:\Temp
Press any key to continue . . .
Le répertoire de travail actuel du processus parent (l'Explorateur Windows en tant que bureau) est utilisé pour exécuter le fichier de commandes car aucun basculement vers une session utilisateur différente n'était nécessaire dans ce cas.
PA a déjà publié 2 solutions possibles dans sa réponse que je reproduis ici avec une petite amélioration (pushd
avec répertoire entre guillemets) et avec en ajoutant un troisième.
Remplacez le répertoire actuel par le répertoire du fichier de commandes en utilisant pushd et popd :
pushd "%~dp0"
%SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
popd
Cela fonctionne également pour les chemins UNC. Exécuter dans une fenêtre d'invite de commandes pushd /?
pour une explication pourquoi cela fonctionne également pour les chemins UNC.
Utilisez le répertoire du fichier de commandes dans les spécifications source et destination:
%SystemRoot%\System32\xcopy.exe "%~dp0File1.txt" "%~dp0File2.txt" /Y
Changez le répertoire de travail en répertoire du fichier de commandes en utilisant cd :
cd /D "%~dp0"
%SystemRoot%\System32\xcopy.exe "File1.txt" "File2.txt" /Y
Cela ne fonctionne pas pour les chemins UNC car l'interpréteur de commandes cmd ne prend pas en charge un chemin UNC comme répertoire actuel par défaut, voir par exemple CMD ne ne prend pas en charge les chemins UNC en tant que répertoires actuels pour plus de détails.
Le message d'erreur est très explicite. Le fichier file1.txt
n'est pas trouvé.
Le nom de fichier n'incluant pas de chemin absolu, le système essaie de le trouver dans le répertoire en cours. Votre répertoire actuel ne contient pas ce fichier.
Votre idée fausse est que le répertoire courant n'est pas le répertoire qui contient le fichier bat. Ce sont deux concepts sans rapport.
Vous pouvez facilement vérifier en ajoutant ces deux commandes dans votre fichier bat
echo BAT directory is %~dp0
echo Current directory is %CD%
vous pouvez remarquer qu'ils sont différents et qu'il y a une différence subtile dans la façon dont la dernière barre oblique inverse est ajoutée ou non.
Donc, il existe essentiellement deux façons de faire face à ce problème
soit changer le répertoire courant pour qu'il corresponde à celui attendu
pushd %~dp0
XCOPY /y "File1.txt" "File2.txt"
popd
ou spécifiez le chemin complet dans la commande
XCOPY /y "%~dp0File1.txt" "%~dp0File2.txt"
Par souci d'exhaustivité et d'obscurité, j'ajoute une autre solution de contournement, confirmée comme fonctionnant sous Windows 8.1 et censée fonctionner ailleurs, car elle repose sur des fonctionnalités documentées:
Vous pouvez modifier les clés de définition de la commande runas
_HKEY_CLASSES_ROOT\batfile\Shell\runas\command
_ et
_HKEY_CLASSES_ROOT\cmdfile\Shell\runas\command
_ en
_%SystemRoot%\System32\cmd.exe /S /C "(for %%G in (%1) do cd /D "%%~dpG") & "%1"" %*
_
Ce qui entraîne le démarrage du fichier bat
ou cmd
dans son répertoire conteneur lors de l'utilisation du verbe runas
, respectivement l'entrée de menu "Exécuter en tant qu'administrateur".
Que font exactement les ajouts à la commande d'origine:
cmd /S
_ supprime la première et la dernière (double) citation dans la chaîne de commande après _/C
_for %%G in (%1) do
énumère sa seule entrée, l'argument _%1
_, le rendant disponible pour l'expansion sous la forme _%%G
_ dans le corps de la boucle; la lettre est arbitraire mais certains peuvent être "réservés"%%~dpG
_ se développe en d rive et p ath de _%%G
_, le ~ tilde supprimant les guillemets si présent, c'est pourquoi nous les rajoutons explicitementcd /D
_ change à la fois le d rive et le répertoire en son argument, et enfin&
_ exécute la deuxième commande _"%1" %*
_ quelle que soit la réussite de la première.Vous pouvez utiliser pushd
qui supportera même les chemins UNC, mais un popd
errant entraînerait n'importe quel script dans le _system32
_ répertoire, pas un comportement que j'aimerais.
Il devrait être également possible pour l'entrée exefile
, mais franchement, je préfère vivre avec l'incohérence que de essayez ceci sur mon système, car toute erreur pourrait casser beaucoup.
Profitez de la défaite des mécanismes de sécurité de votre système d'exploitation :)