Могу ли я замаскировать вводимый текст в файле bat - PullRequest
90 голосов
/ 20 марта 2009

Я пишу командный файл для выполнения некоторых других программ. В этом случае мне нужно запросить пароль. У меня есть какой-нибудь способ замаскировать вводимый текст. Мне не нужно печатать символы ******* вместо вводимых символов. Поведение запроса пароля в Linux (ничего не печатать во время набора) достаточно.

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

Это будет читать ввод, но я не могу замаскировать текст, используя этот подход.

Ответы [ 14 ]

140 голосов
/ 03 декабря 2013

Да - я опоздал на 4 года.

Но я нашел способ сделать это в одной строке без необходимости создания внешнего скрипта; путем вызова команд powershell из командного файла.

Благодаря TessellatingHeckler - без вывода в текстовый файл (я установил команду powershell в переменной, потому что она довольно грязная в одной длинной строке внутри цикла 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%

Первоначально я написал его для вывода в текстовый файл, а затем прочитал из этого текстового файла. Но вышеуказанный метод лучше. В одной чрезвычайно длинной, почти непонятной строке:

@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%

Я разобью это - вы можете разбить его на несколько строк, используя каретку ^, что намного лучше ...

@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%

В этой статье объясняется, что делают команды powershell; по сути, он получает ввод с помощью Read-Host -AsSecureString - следующие две строки преобразуют эту защищенную строку обратно в обычный текст, затем вывод (незашифрованный пароль) отправляется в текстовый файл с использованием >.tmp.txt. Этот файл затем читается в переменную и удаляется.

49 голосов
/ 20 марта 2009

До XP и Server 2003 вы можете использовать другой включенный инструмент (VBScript) - следующие два скрипта выполняют нужную вам работу.

Сначала getpwd.cmd:

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

Тогда getpwd.vbs:

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

getpwd.vbs просто использует объект пароля для ввода пароля от пользователя, а затем выводит его на стандартный вывод (в следующем параграфе будет объяснено, почему он не отображается в терминале).

Командный скрипт getpwd.cmd немного сложнее, но в основном работает следующим образом.

Эффект команды "<nul: set /p passwd=Password: " состоит в выводе приглашения без завершающего символа новой строки - это хитрый способ эмулировать команду "echo -n" из оболочки bash. Он устанавливает passwd в пустую строку как несущественный побочный эффект и не ждет ввода, так как принимает данные от устройства nul:.

Оператор "for /f "delims=" %%i in ('cscript /nologo getpwd.vbs') do set passwd=%%i" - самый хитрый бит. Он запускает VBScript без «рекламы» Microsoft, поэтому единственной строкой вывода является пароль (из VBscript "Wscript.StdOut.WriteLine strPassword".

Установка разделителей на ничто не требуется для захвата всей строки ввода с пробелами, в противном случае вы просто получите первое слово. Бит "for ... do set ..." устанавливает passwd как фактический пароль, выводимый из VBScript.

Затем мы выводим пустую строку (для завершения строки "Password: "), и пароль будет в переменной окружения passwd после выполнения кода.


Теперь, как уже упоминалось, scriptpw.dll доступен только до XP / 2003. Чтобы исправить это, вы можете просто скопировать файл scriptpw.dll из папки Windows\System32 системы XP / 2003 в папку Winnt\System32 или Windows\System32 в вашей собственной системе. После того, как DLL была скопирована, вам нужно зарегистрировать ее, выполнив:

regsvr32 scriptpw.dll

Чтобы успешно зарегистрировать DLL в Vista и более поздних версиях, вам потребуются права администратора. Я не изучал законность такого шага, поэтому пещерный лектор.


Если вы не чрезмерно заинтересованы в попытке отследить и зарегистрировать старые файлы DLL (для удобства или по юридическим причинам), есть другой способ. Более поздние версии Windows (те, которые не не имеют требуемой DLL) должны иметь доступную вам Powershell.

И, на самом деле, вам действительно стоит подумать об обновлении ваших сценариев, чтобы использовать их полностью, поскольку это гораздо более мощный язык сценариев, чем cmd.exe. Однако, если вы хотите сохранить большую часть кода в виде cmd.exe сценариев (например, если у вас есть много кода, который вы не хотите преобразовывать), вы можете использовать тот же прием.

Во-первых, измените скрипт cmd так, чтобы он вызывал Powershell, а не CScript:

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

Сценарий Powershell одинаково прост:

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

хотя с некоторой сортировкой, чтобы получить фактический текст пароля.

Помните, что для запуска локальных неподписанных сценариев Powershell на вашем компьютере вам может потребоваться изменить политику выполнения по умолчанию (драконовская, хотя и очень безопасная), например:

set-executionpolicy remotesigned

изнутри самого Powershell.

23 голосов
/ 25 июня 2014

1.Чистое пакетное решение , которое (ab) использует команду XCOPY и его /P /L найдены переключатели здесь (некоторые улучшения этого можно найти здесь ):

:: 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 Другой способ, основанный на команде замены

@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. Отправитель пароля, использующий всплывающее окно HTA , Это гибридный файл .bat / jscript / mshta , который должен быть сохранен как .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. Самокомпилируемый гибрид .net . Усиление должно быть сохранено как .bat. В отличие от других решений, оно будет создавать / компилировать маленький файл .exe, который будет вызываться (если вы хотите, вы можете удалить его). Также требуется установленный .net framework, но это не проблема:

@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);
12 голосов
/ 20 марта 2009

Я бы, наверное, просто сделал:

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

Таким образом, вы получаете приглашение, затем экран очищается после его ввода.

Обратите внимание, что введенный пароль будет сохранен в истории CMD, если командный файл будет выполнен из командной строки (Спасибо @ Mark K Cowan ).

Если бы этого было недостаточно, я бы либо переключился на python, либо написал бы исполняемый файл вместо скрипта.

Я знаю, что ни одно из этих идеальных решений не подходит, но, может быть, один достаточно хорош для вас:)

6 голосов
/ 27 мая 2009

другой альтернативой являются мои инструменты командной строки EditV32 (x86) или EditV64 (x64). Например:

editv32 -m -p "Password: " PWD

-m означает «маскированный ввод», а -p - приглашение. Вводимые пользователем данные хранятся в переменной среды PWD. Вы можете получить его здесь:

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

4 голосов
/ 14 сентября 2015

Если у вас установлен Python, вы можете использовать:

for /f "delims=" %%A in ('python -c "import getpass; print(getpass.getpass('Enter the CVS password: '));"') do @set CVSPASS=%%A
echo PASS: %CVSPASS%

вывод:

Enter the CVS password:
PASS: 123
4 голосов
/ 17 июля 2014

Вы можете использовать подпрограмму ReadFormattedLine для всех видов форматированного ввода. Например, приведенная ниже команда считывает пароль из 8 символов, отображает звездочки на экране и продолжает автоматически, не нажимая Enter:

call :ReadFormattedLine password="********" /M "Enter password (8 chars): "

Эта подпрограмма написана в чистом пакетном режиме, поэтому для нее не требуется никакой дополнительной программы, и она позволяет выполнять несколько форматированных операций ввода, таких как чтение только чисел, преобразование букв в верхний регистр и т. Д. Вы можете загрузить подпрограмму ReadFormattedLine из * 1004 строка с определенным форматом .


РЕДАКТИРОВАТЬ 2018-08-18 : Новый способ ввода «невидимого» пароля

У команды FINDSTR есть странная ошибка, которая возникает, когда эта команда используется для отображения цветных символов И выходные данные такой команды перенаправляются на устройство CON. Подробнее о том, как использовать команду FINDSTR для отображения текста в цвете, см. этот раздел .

Когда вывод этой формы команды FINDSTR перенаправляется на CON, происходит нечто странное после того, как текст выводится в желаемом цвете: весь текст после него выводится как «невидимые» символы, хотя более точное описание состоит в том, что текст выводится как черный текст на черном фоне. Исходный текст появится, если вы используете команду COLOR для сброса цветов переднего плана и фона всего экрана. Однако, когда текст «невидим», мы можем выполнить команду SET / P, поэтому все введенные символы не будут отображаться на экране.

@echo off
setlocal

set /P "=_" < NUL > "Enter password"
findstr /A:1E /V "^$" "Enter password" NUL > CON
del "Enter password"
set /P "password="
cls
color 07
echo The password read is: "%password%"
4 голосов
/ 17 мая 2014

Если вас беспокоит отсутствие исходного кода, у меня есть другая альтернатива.

@echo off
for /f "delims=" %%p in ('ReadLine -h -p "Enter password: "') do set PWD=%%p
echo You entered: %PWD%

Вы можете получить его от https://westmesatech.com/?page_id=49. Исходный код включен.

1 голос
/ 18 июля 2014

UPDATE:
Я добавил два новых метода, которые вместо использования cls для скрытия ввода создают новое всплывающее окно только с одной строкой.

Недостатки в том, что один метод (метод 2) оставляет ненужную запись в реестре - «Если выполняется без надлежащих прав», а другой (метод три) добавляет некоторую ненужную информацию в сценарий. Само собой разумеется, что это может легко быть записано в любой файл TMP и удалено, я только попытался придумать альтернативу.

Ограничение: Пароль может быть только буквенно-цифровым - никаких других символов!

@echo off
if "%1"=="method%choice%" goto :method%choice%
::::::::::::::::::
::Your code here::
::::::::::::::::::
cls
echo :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
echo ::::                   Batch script to prompt for password!                 :::
echo :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:choice
echo.
echo 1. First method
echo.
echo 2. Second method
echo.
echo 3. Third method
echo.
set/p choice=Choose a method: 
if "%choice%" gtr "3" echo. & echo invalid option & echo. & pause & goto choice

call :vars
    set options= %num%%smAlph%%cpAlph%
    set pwdLen=6

if "%choice%" == "1" (
    set /p=Password: <nul 
    for /l %%i in (1,1,%pwdLen%) do call :password
) else (
    start /wait cmd /c call "%~f0" method%choice%
    )

call :result%choice%


::just to see if it worked!
echo.
echo The Password you entered is: "%pwd%"&pause>nul

::::::::::::::::::
::More code here::
::::::::::::::::::
exit /b





:vars
set num=1234567890
set smAlph=abcdefghijklmnopqrstuvwxyz
set cpAlph=ABCDEFGHIJKLMNOPQRSTUVWXYZ
    set pwd=
goto :EOF


:method2
call :popUp
setx result %pwd% >nul
goto :EOF

:method3
call :popUp
    >> "%~f0" echo.
    >> "%~f0" echo :result%choice%
    >> "%~f0" echo set pwd=%pwd%
goto :EOF

:popUp
title Password
mode con lines=1 cols=30
color 5a
set /p=Password: <nul
for /l %%i in (1,1,%pwdLen%) do call :password
goto :EOF

:password
:: If you don't want case sensative remove "/cs" but remember to remove %cpAlph% from the %options%
choice /c %options% /n /cs >nul
    call SET pwd=%pwd%%%options:~%errorlevel%,1%%
    set /p =*<nul
GOTO :EOF


:result2
for /f "tokens=3" %%a in ('reg query hkcu\environment /v result') do set pwd=%%a
    setx result "" >nul
    reg delete hkcu\environment /v result /f >nul 2>&1
:result1
goto :EOF   
::You can delete from here whenever you want.

Обновление: Я обнаружил, что сообщение sachadee идеально подходит , и я просто добавил к нему свое "всплывающее окно".

@Echo Off  
  SetLocal EnableDelayedExpansion
  if "%1"==":HInput" goto :HInput
  set r=r%random%
  start /wait cmd /c call "%~f0" :HInput

For /f "tokens=2,13 delims=, " %%a in (
    'tasklist /v /fo csv /fi "imagename eq cmd.exe"
    ^|findstr /v "Windows\\system32\\cmd.exe"
    ^|findstr "set /p=%r%"'
     ) do (
        set pid=%%a
        set Line=%%b
        set Line=!Line:%r%=!
        set Line=!Line:~,-2!
        )       
taskkill /pid %pid:"=%>nul
  goto :HIEnd


  :HInput
  SetLocal DisableDelayedExpansion
  title Password
  mode con lines=2 cols=30

Echo Enter your Code :
   Set "Line="
   For /F %%# In (
   '"Prompt;$H&For %%# in (1) Do Rem"'
   ) Do Set "BS=%%#"

  :HILoop
   Set "Key="
   For /F "delims=" %%# In (
   'Xcopy /W "%~f0" "%~f0" 2^>Nul'
   ) Do If Not Defined Key Set "Key=%%#"
   Set "Key=%Key:~-1%"
   SetLocal EnableDelayedExpansion
   If Not Defined Key start /min cmd /k mode con lines=1 cols=14 ^&set/p %r%!Line!=&exit
  If %BS%==^%Key% (Set /P "=%BS% %BS%" <Nul
   Set "Key="
   If Defined Line Set "Line=!Line:~0,-1!"
   ) Else Set /P "=*" <Nul
   If Not Defined Line (EndLocal &Set "Line=%Key%"
   ) Else For /F delims^=^ eol^= %%# In (
   "!Line!") Do EndLocal &Set "Line=%%#%Key%"
  Goto :HILoop

  :HIEnd
   Echo(
Echo Your code is :  "!Line!"
   Pause
   Goto :Eof
1 голос
/ 10 февраля 2013

создайте пакетный файл, который вызывает тот, который необходим для невидимых символов, затем создайте ярлык для вызываемого пакетного файла.

клик правой кнопкой мыши

свойства

цвет

текст == черный

фон == черный

применить

ки

надежда, таким образом, помогает вам !!!!!!!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...