103 votes

Puis-je masquer un texte d'entrée dans un fichier bat ?

J'écris un fichier batch pour exécuter d'autres programmes. Dans ce cas, je dois demander un mot de passe. Existe-t-il un moyen de masquer le texte d'entrée ? Je n'ai pas besoin d'imprimer les caractères ******* à la place des caractères d'entrée. Le comportement de l'invite de mot de passe de Linux (ne rien imprimer pendant la saisie) est suffisant.

@echo off
SET /P variable=Password : 
echo %variable%
Pause

Cela permet de lire l'entrée mais je ne peux pas masquer le texte en utilisant cette approche.

1 votes

165voto

unclemeat Points 1777

Oui - j'ai 4 ans de retard.

Mais j'ai trouvé un moyen de le faire en une ligne sans avoir à créer un script externe ; en appelant des commandes powershell à partir d'un fichier batch.

Merci à TessellatingHeckler - sans sortie vers un fichier texte (j'ai placé la commande powershell dans une variable, parce que c'est plutôt désordonné dans une longue ligne à l'intérieur d'une boucle for).

@echo off
set "psCommand=powershell -Command "$pword = read-host 'Enter Password' -AsSecureString ; ^
    $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword); ^
        [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)""
for /f "usebackq delims=" %%p in (`%psCommand%`) do set password=%%p
echo %password%

À l'origine, je l'avais écrit pour qu'il sorte dans un fichier texte, puis qu'il lise à partir de ce fichier texte. Mais la méthode ci-dessus est meilleure. En une ligne extrêmement longue et presque incompréhensible :

@echo off
powershell -Command $pword = read-host "Enter password" -AsSecureString ; $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword) ; [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) > .tmp.txt & set /p password=<.tmp.txt & del .tmp.txt
echo %password%

Je vais décomposer cela - vous pouvez le répartir sur quelques lignes en utilisant le caret ^ ce qui est beaucoup plus agréable...

@echo off
powershell -Command $pword = read-host "Enter password" -AsSecureString ; ^
    $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword) ; ^
        [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) > .tmp.txt 
set /p password=<.tmp.txt & del .tmp.txt
echo %password%

Cet article explique ce que font les commandes powershell ; essentiellement, il reçoit des entrées en utilisant Read-Host -AsSecureString - les deux lignes suivantes reconvertissent cette chaîne sécurisée en texte clair, la sortie (mot de passe en texte clair) est ensuite envoyée dans un fichier texte en utilisant la fonction >.tmp.txt . Ce fichier est ensuite lu dans une variable et supprimé.

6 votes

La réponse originale était excellente, mais je pense que celle-ci devrait être la réponse définitive maintenant.

35 votes

C'est génial. Mais la façon dont il enregistre un mot de passe en texte clair sur le disque me met mal à l'aise. Évitez de le faire en faisant ceci à la place : for /f "usebackq tokens=*" %%p in (``powershell -Command "$pword = read-host 'Enter Password' -AsSecureString ; $BSTR=[System.Runtime.InteropServices.Marshal]::SecureString‌​ToBSTR($pword); [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($B‌​STR)"``) do set password=%%p et ensuite echo %password% . NB. Je n'arrive pas à faire en sorte que ce commentaire échappe correctement aux barres obliques - avant "powershell", et avant la fin ")", il y a deux barres obliques, alors qu'il devrait y en avoir une seule.

2 votes

@TessellatingHeckler Bonne idée, j'ai mis à jour ma réponse. Une version légèrement modifiée de votre suggestion. Merci.

51voto

paxdiablo Points 341644

Jusqu'à XP et Server 2003, vous pouvez utiliser un autre outil inclus (VBScript) - les deux scripts suivants font le travail que vous voulez.

D'abord, getpwd.cmd :

@echo off
<nul: set /p passwd=Password: 
for /f "delims=" %%i in ('cscript /nologo getpwd.vbs') do set passwd=%%i
echo.

Ensuite, getpwd.vbs :

Set oScriptPW = CreateObject("ScriptPW.Password")
strPassword = oScriptPW.GetPassword()
Wscript.StdOut.WriteLine strPassword

Le site getpwd.vbs utilise simplement l'objet password pour saisir le mot de passe de l'utilisateur et l'imprimer sur la sortie standard (le paragraphe suivant expliquera pourquoi cela ne s'affiche pas dans le terminal).

Le site getpwd.cmd La commande script est un peu plus délicate mais elle fonctionne essentiellement comme suit.

L'effet de la "<nul: set /p passwd=Password: " consiste à afficher l'invite sans caractère de fin de ligne - c'est une façon sournoise d'émuler la commande "echo -n" à partir du bash coquille. Il définit passwd à une chaîne vide en tant qu'effet secondaire non pertinent et n'attend pas d'entrée puisqu'il prend son entrée à partir de l'élément nul: appareil.

Le site "for /f "delims=" %%i in ('cscript /nologo getpwd.vbs') do set passwd=%%i" La déclaration est la partie la plus délicate. Elle exécute le VBScript sans aucune "publicité" Microsoft, de sorte que la seule ligne de sortie est le mot de passe (du VBscript "Wscript.StdOut.WriteLine strPassword" .

La définition des délimiteurs à rien est nécessaire pour capturer une ligne d'entrée entière avec des espaces, sinon vous obtenez juste le premier mot. Le site "for ... do set ..." le bit est activé passwd pour être le mot de passe réel produit par le VBScript.

Ensuite, nous affichons une ligne blanche (pour mettre fin à l'exécution de l'opération). "Password: " ) et le mot de passe sera dans la ligne passwd après l'exécution du code.


Maintenant, comme mentionné, scriptpw.dll n'est disponible que jusqu'à XP/2003. Pour remédier à cela, vous pouvez simplement copier le fichier scriptpw.dll à partir du fichier Windows\System32 d'un système XP/2003 vers le dossier Winnt\System32 ou Windows\System32 sur votre propre système. Une fois que la DLL a été copiée, vous devrez l'enregistrer en exécutant :

regsvr32 scriptpw.dll

Pour réussir à enregistrer la DLL sur Vista et les versions ultérieures, vous aurez besoin des privilèges d'administrateur. Je n'ai pas examiné la légalité d'un tel mouvement, alors cave lector.


Si vous n'êtes pas excessivement Si vous ne voulez pas essayer de retrouver et d'enregistrer d'anciens fichiers DLL (pour des raisons pratiques ou juridiques), il existe une autre solution. Les versions ultérieures de Windows (celles qui Ne le fais pas. ont la DLL requise) devraient avoir Powershell à leur disposition.

En fait, vous devriez vraiment envisager de mettre à niveau vos scripts pour l'utiliser pleinement, car il s'agit d'un langage de script bien plus performant que le langage cmd.exe . Cependant, si vous voulez garder la majeure partie de votre code en tant que cmd.exe (par exemple, si vous disposez d'un script lot de code que vous ne voulez pas convertir), vous pouvez utiliser la même astuce.

Tout d'abord, modifiez le cmd script pour qu'il appelle Powershell plutôt que CScript :

@echo off
for /f "delims=" %%i in ('powershell -file getpwd.ps1') do set passwd=%%i

Le script de Powershell est tout aussi simple :

$password = Read-Host "Enter password" -AsSecureString
$password = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
$password = [Runtime.InteropServices.Marshal]::PtrToStringAuto($password)
echo $password

bien qu'avec un peu de marshalling pour obtenir le texte réel du mot de passe.

N'oubliez pas que, pour exécuter des scripts Powershell locaux non signés sur votre machine, vous devrez peut-être modifier la politique d'exécution par rapport à la politique par défaut (draconienne, mais très sûre), avec quelque chose comme :

set-executionpolicy remotesigned

à partir de Powershell lui-même.

2 votes

Whoa, ce <nul : set /p est vraiment cool. Je ne le savais pas jusqu'à présent :-). Mais le VBScript ne fonctionne pas pour moi : Microsoft VBScript runtime error : Le composant ActiveX ne peut pas créer l'objet : 'ScriptPW.Password'. Windows 7 Beta x64 ici.

0 votes

Intéressant, c'est censé être disponible à partir de XP. Je soupçonne que Win7 n'est pas encore tout à fait terminé si ça ne fonctionne pas là (ou si vous devez faire une autre astuce pour que ça fonctionne). Un peu de recherche montre pourquoi : voir ma mise à jour.

2 votes

Joli. Il est également bon de noter que vous pouvez remplacer le fichier VBS par tout langage équivalent pouvant être appelé depuis la ligne de commande. Par exemple, vous pouvez remplacer la section cscript par : 'python -c "from getpass import getpass ; pwd = getpass() ; print pwd ;"'

25voto

npocmaka Points 7794

1. solution de lot pur qui (ab)utilise XCOPY et de son /P /L interrupteurs trouvés ici (certaines améliorations pourraient être apportées se trouvent ici ) :

:: Hidden.cmd
::Tom Lavedas, 02/05/2013, 02/20/2013
::Carlos, 02/22/2013
::https://groups.google.com/forum/#!topic/alt.msdos.batch.nt/f7mb_f99lYI

@Echo Off
:HInput
SetLocal EnableExtensions EnableDelayedExpansion
Set "FILE=%Temp%.\T"
Set "FILE=.\T"
Keys List >"%File%"
Set /P "=Hidden text ending with Ctrl-C?: " <Nul
Echo.
Set "HInput="
:HInput_
For /F "tokens=1* delims=?" %%A In (
 '"Xcopy /P /L "%FILE%" "%FILE%" 2>Nul"'
) Do (
  Set "Text=%%B"
  If Defined Text (
    Set "Char=!Text:~1,1!"
    Set "Intro=1"
    For /F delims^=^ eol^= %%Z in ("!Char!") Do Set "Intro=0"
    Rem If press Intro
    If 1 Equ !Intro! Goto :HInput#
    Set "HInput=!HInput!!Char!"
  )
)
Goto :HInput_
:HInput#
Echo(!HInput!
Goto :Eof 

1.2 Un autre moyen basé sur la commande de remplacement

@Echo Off
SetLocal EnableExtensions EnableDelayedExpansion

Set /P "=Enter a Password:" < Nul
Call :PasswordInput
Echo(Your input was:!Line!

Goto :Eof

:PasswordInput
::Author: Carlos Montiers Aguilera
::Last updated: 20150401. Created: 20150401.
::Set in variable Line a input password
For /F skip^=1^ delims^=^ eol^= %%# in (
'"Echo(|Replace.exe "%~f0" . /U /W"') Do Set "CR=%%#"
For /F %%# In (
'"Prompt $H &For %%_ In (_) Do Rem"') Do Set "BS=%%#"
Set "Line="
:_PasswordInput_Kbd
Set "CHR=" & For /F skip^=1^ delims^=^ eol^= %%# in (
'Replace.exe "%~f0" . /U /W') Do Set "CHR=%%#"
If !CHR!==!CR! Echo(&Goto :Eof
If !CHR!==!BS! (If Defined Line (Set /P "=!BS! !BS!" <Nul
Set "Line=!Line:~0,-1!"
)
) Else (Set /P "=*" <Nul
If !CHR!==! (Set "Line=!Line!^!"
) Else Set "Line=!Line!!CHR!"
)
Goto :_PasswordInput_Kbd

2.Soumissionnaire de mot de passe qui utilise un pop-up HTA . Il s'agit d'un hybrit .bat/jscript/mshta. et doit être enregistré en tant que fichier .bat :

<!-- :
:: PasswordSubmitter.bat
@echo off
for /f "tokens=* delims=" %%p in ('mshta.exe "%~f0"') do (
    set "pass=%%p"
)

echo your password is %pass%
exit /b
-->

<html>
<head><title>Password submitter</title></head>
<body>

    <script language='javascript' >
        window.resizeTo(300,150);
        function entperPressed(e){
                if (e.keyCode == 13) {
                    pipePass();
                }
        }
        function pipePass() {
            var pass=document.getElementById('pass').value;
            var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
            close(fso.Write(pass));

        }
    </script>

    <input type='password' name='pass' size='15' onkeypress="return entperPressed(event)" ></input>
    <hr>
    <button onclick='pipePass()'>Submit</button>

</body>
</html>

3. Un hybride .net auto-compilé .Again doit être enregistré comme .bat À la différence des autres solutions, il crée/compile un petit fichier .exe qui sera appelé (si vous le souhaitez, vous pouvez le supprimer). Il faut également installer .net framework mais ce n'est pas un problème :

@if (@X)==(@Y) @end /* JScript comment
@echo off
setlocal enableDelayedExpansion

for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
   set "jsc=%%v"
)

if not exist "%~n0.exe" (
    "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)

for /f "tokens=* delims=" %%p in ('"%~n0.exe"') do (
    set "pass=%%p"
)

echo your password is !pass!

endlocal & exit /b %errorlevel%

*/

import System;

var pwd = "";
var key;

Console.Error.Write("Enter password: ");

        do {
           key = Console.ReadKey(true);

           if ( (key.KeyChar.ToString().charCodeAt(0)) >= 20 && (key.KeyChar.ToString().charCodeAt(0) <= 126) ) {
              pwd=pwd+(key.KeyChar.ToString());
              Console.Error.Write("*");
           }

           if ( key.Key == ConsoleKey.Backspace && pwd.Length > 0 ) {
               pwd=pwd.Remove(pwd.Length-1);
               Console.Error.Write("\b \b");
           }

        } while (key.Key != ConsoleKey.Enter);
        Console.Error.WriteLine();
        Console.WriteLine(pwd);

6 votes

Mon sens du bricolage me picote, surtout au niveau de l'hybride !

2 votes

Cette première solution est très astucieuse - bien joué +1.

0 votes

La méthode 2.1 basée sur la commande remplacer manquera des frappes si vous tapez rapidement.

16voto

Blorgbeard Points 38991

Je le ferais probablement :

..
echo Before you enter your password, make sure no-one is looking!
set /P password=Password:  
cls
echo Thanks, got that.
.. 

Vous recevez donc une invite, puis l'écran s'efface après la saisie.

Notez que le mot de passe saisi sera stocké dans l'historique CMD si le fichier batch est exécuté à partir d'une invite de commande (Merci @Mark K Cowan ).

Si cela ne suffisait pas, je passerais à python, ou j'écrirais un exécutable au lieu d'un script.

Je sais qu'aucune de ces soutions n'est parfaite, mais peut-être que l'une d'entre elles est assez bonne pour vous :)

5 votes

Notez que le mot de passe saisi sera stocké dans l'historique CMD si le fichier batch est exécuté à partir d'une invite de commande. Pas de downvote cependant, car vous avez bien dit que cmd n'est pas le bon outil pour ce travail.

0 votes

Vous pouvez exécuter doskey /reinstall pour effacer le tampon de commande précédent immédiatement après cls si l'historique des commandes dans la console n'est pas important pour vous.

1 votes

Si vous ne voulez pas utiliser doskey /reinstall et effacer l'historique des commandes, une autre option consiste à exécuter le code ci-dessus dans une fenêtre de terminal séparée et à la quitter immédiatement. Notez que cela ne remplace toujours pas la chaîne de caractères que vous avez tapée par des astérisques. La solution ci-dessus est une option si vous ne voulez pas exécuter powershell. C:\>start "console" cmd /c ireadconsole.bat

6voto

Bill_Stewart Points 2460

Une autre alternative est mes outils de ligne de commande EditV32 (x86) ou EditV64 (x64). Par exemple :

editv32 -m -p "Password: " PWD

-m signifie "entrée masquée" et -p est l'invite. L'entrée de l'utilisateur est stockée dans la variable d'environnement PWD. Vous pouvez l'obtenir ici :

https://westmesatech.com/?page_id=19

5 votes

Ce n'est pas la seule solution à source fermée (Windows est à source fermée !). Vous êtes libre de ne pas l'utiliser, bien sûr...

0 votes

Si l'absence de code source vous dérange, consultez mon autre réponse concernant l'absence de code source. ReadLine.exe .

0 votes

Bien joué ! La licence vous permet de l'utiliser. De plus, il est facile à intégrer. Juste pour gérer le code de sortie 1. Erreur sur la ligne de commande, 2 La ligne de saisie était vide, 3 La variable d'environnement n'a pas été modifiée, 4 Le programme a été interrompu avec Ctrl-C.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X