我正在编写批处理文件以执行其他程序。在这种情况下,我需要提示输入密码。是否有一种方法可以掩盖输入文本?我不需要用*******字符代替输入字符。类似Linux的密码提示行为(输入时不显示任何内容)就足够了。
@echo off
SET /P variable=Password :
echo %variable%
Pause
这将读取输入,但我无法使用此方法掩盖文本。
我正在编写批处理文件以执行其他程序。在这种情况下,我需要提示输入密码。是否有一种方法可以掩盖输入文本?我不需要用*******字符代替输入字符。类似Linux的密码提示行为(输入时不显示任何内容)就足够了。
@echo off
SET /P variable=Password :
echo %variable%
Pause
这将读取输入,但我无法使用此方法掩盖文本。
是的 - 我晚了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
发送到文本文件。该文件随后被读入变量并删除。
for /f "usebackq tokens=*" %%p in (
powershell -Command "$pword = read-host 'Enter Password' -AsSecureString ; $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword); [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)") do set password=%%p
,然后使用 echo %password%
。注意:我无法正确转义回撤字符 - 在 "powershell" 前面和 ")" 结尾前都应该有一个反引号,但应该只有一个反引号。 - TessellatingHeckler在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: "
命令的效果是输出提示符而没有换行符-这是模拟bash
shell中的"echo -n"
命令的一个狡猾的方法。它将passwd
设置为空字符串作为不相关的副作用,并且不等待输入,因为它正在从nul:
设备中获取输入。
"for /f "delims=" %%i in ('cscript /nologo getpwd.vbs') do set passwd=%%i"
语句是最棘手的部分。它在没有微软“广告”的情况下运行VBScript,因此输出的唯一一行是密码(来自VBScript的"Wscript.StdOut.WriteLine strPassword"
)。
将定界符设置为空是捕获具有空格的整个输入行所必需的,否则您只会得到第一个单词。 "for ... do set ..."
部分将passwd
设置为从VBScript输出的实际密码。
然后我们输出一个空行(以终止"Password: "
行),在代码运行后,密码将在passwd
环境变量中。
如前所述,scriptpw.dll
仅适用于XP/2003。为解决这个问题,您可以从XP/2003系统的Windows\System32
文件夹复制scriptpw.dll
文件到自己系统的Winnt\System32
或Windows\System32
文件夹中。复制DLL后,您需要通过运行以下命令来注册它:
regsvr32 scriptpw.dll
要想在Vista及更高版本的操作系统上成功注册DLL,你需要管理员权限。我并没有检查这样做的合法性,所以请小心。
如果您不是非常热衷于试图追踪和注册旧的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本身内部执行。
ScriptPW.Password
对象只存在于 Windows XP 中。更新的版本没有它。 - Bill_Stewartscriptpw.dll
。 - paxdiablo1.纯批处理方案,滥用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);
我可能会这样做:
..
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,要么会编写一个可执行文件而不是脚本。
我知道这些都不是完美的解决方案,但也许其中一个对你来说已经足够好了 :)
cls
后立即运行 doskey /reinstall
来清除先前的命令缓冲区。 - RuntimeExceptionC:\> start“console”cmd /c ireadconsole.bat
- RuntimeExceptionSET /P pw=C:\^>
^ 转义了 >,这样密码提示就会看起来像标准的 cmd 控制台提示。 - nmbell您可以使用ReadFormattedLine子程序进行各种格式化输入。例如,以下命令读取8个字符的密码,在屏幕上显示星号,并自动继续而无需按Enter键:
call :ReadFormattedLine password="********" /M "Enter password (8 chars): "
编辑于2018年08月18日:输入“隐形”密码的新方法
FINDSTR命令存在一个奇怪的bug,当使用该命令以彩色显示字符并将其输出重定向到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%"
另一种选择是我的EditV32(x86)或EditV64(x64)命令行工具。例如:
editv32 -m -p "Password: " PWD
请注意保留原有的HTML标记。
:: see https://stackoverflow.com/questions/33293220/what-is-the-fastest-color-function-in-batch
@echo off
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
set color_white=%ESC%[37m
set color_black=%ESC%[30m
echo(
set /p user=Username:
set /p pass=password:%color_black%
echo %color_white%
echo blablablba
享受吧!!!
echo off
的情况下才能按预期工作,否则 set
命令已经改变了颜色。当然,如果背景颜色已经是黑色(默认情况下是这样的,但您不能依赖它)。不错的发现(尽管我怀疑它在2009年就能起作用)。 - Stephanfor /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
@echo off
for /f "delims=" %%p in ('ReadLine -h -p "Enter password: "') do set PWD=%%p
echo You entered: %PWD%
我使用了Blorgbeard提供的解决方案,我认为它非常好。然后我进行了以下增强:
像这样使用它:
@echo off
ansicon -p
set /p pwd=Password:ESC[0;37;47m
echo ESC[0m
这将在输入密码时将控制台切换到灰色,完成后再切换回来。ESC实际上应该是一个不可打印的字符,您可以从下载的示例文本文件中复制(在记事本中看起来像左箭头),然后粘贴到批处理文件中。您可以使用示例文本文件查找所有颜色组合的代码。
如果您不是计算机管理员,则可能能够将文件安装在非系统目录中,然后在调用程序并使用转义序列之前,在脚本中将目录添加到PATH中。如果您需要一个非管理员可分发的仅包含几个文件的软件包,则这甚至可能是当前目录。