Get logon username in elevated script with standard user account - windows

In my batch script run within Windows 7, I have several IF clauses like:
IF "%USERNAME%"=="foo" GOTO bar
Unfortunately, when I run this batch script elevated with "Run as administrator" from the Context Menu, the %USERNAME% is always the administrator's username, not the username of the current active logon user.
The same applies to whoami in an elevated batch script.
QUERY USER gives me a list of all users currently logged on, not merely the one user I am looking for.
A standard user account, unlike an administrator account that can elevate from user group token to administrator group token while keeping the same user environment, actually loads the administrator account environment when "Run as administrator" is selected.
Is there a way to get the current active logon username instead of the administrators username?

WMIC ComputerSystem Get UserName
#echo off
setlocal
rem Get logon username without the leading "computername\" string.
set "user="
for /f "skip=1 tokens=1,* delims=\" %%A in (
'wmic computersystem get username ^|findstr /r /v "^$"'
) do for %%C in (%%~B) do if not defined user set "user=%%~C"
echo "%user%"
pause
Using the for /f option skip=1, as the 1st line is the UserName header that is not wanted. Delimit by \ as the value will be like computername\username and get the remainder in the 2nd token. Pipe to findstr to ignore empty lines. 2nd for loop will get the first value free of whitespace characters.
Piping wmic output to powershell to cleanup the output tests better than piping to findstr, and the use of a 2nd for loop is not needed.
#echo off
setlocal
rem Get logon username without the leading "computername\" string.
set "user="
for /f "skip=1 tokens=1,* delims=\" %%A in ('
wmic computersystem get username ^|
powershell -noprofile -command "$input.trim()"
') do set "user=%%~B"
echo "%user%"
pause
Use command /? for more help. Most commands in the code will display help with the /? argument at a Command Prompt.
Query User alias QUser
#echo off
setlocal
rem Get logon username.
set "user="
for /f %%A in ('quser^|findstr /b /c:">"') do set "user=%%~A"
if defined user if "%user:~0,1%" == ">" set "user=%user:~1%"
echo "%user%"
pause
The leading > in quser (an alias for query user) indicates the currently logged on username, not the administrator's username.
Use %user% instead of %username% where needed.
Notes:
Due to for /f loop getting username from the default option of token=1, if username contains a space or tab, then this will get only the characters that precede the space or tab.
On a 64 bit OS, quser.exe exists in System32, not in SysWOW64. A 32 bit cmd.exe on a 64 bit OS may not be recognized as a command.
References:
query user
Query User / QUSER

Related

How to identify the current logged in user of a windows 10 machine

I have developed a software, that requires current logged in user name, but during the installation, I provide the admin user( admin right user). my application fetches the admin user. is there any way to get the current user name/ details from the registry.
I tried to fetch the HKEY_CURRENT_USER, however, it returns the admin user profile.
I'm not exactly sure why you'd want to get this from the registry via batch file, but if you just want to get it in a batch file, just look at the %username% environment variable. Alternatively if you want to get domain\machine information, check the output of whoami. Lastly if you want a bit more information and want to parse it, you can use Query user but that would be decidedly more messy.
C:\Users\myname>echo %username%
myname
Or
C:\Users\myname>whoami
domain\myname
I don't know if this what you want as to query the value of LastUsedUsername ?
#echo off
set "Winlogonkey=HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
#for /f "tokens=3 skip=2 delims= " %%a in (
'Reg Query "%Winlogonkey%" /v LastUsedUsername'
) do (
Set "LastUsedUsername=%%a"
)
echo "%LastUsedUsername%"
pause

SC Query returns errors when used in BATCH FILE 'FOR' loop

Trying to use the following line of code in a Batch File FOR loop:
FOR /F "delims=" %%g IN ('sc query type=service ^| FIND /I "bthserv"') DO ( ECHO %%g )
The command in brackets works successfully when used from CMD Prompt.
However, in a FOR loop it simply returns:
[SC] EnumQueryServicesStatus:OpenService FAILED 123:
The filename, directory name, or volume label syntax is incorrect.
Is anyone familiar with this error and how to get the FOR loop to report all services with the specific, or similar name(s)?
[Edit /]
Even changing the command to this fails with the same message:
FOR /F "delims=" %%g IN ('sc query type^= service ^| FIND /I "bthserv"') DO ( ECHO %%g )
To begin with, your title is confusing because it uses queryex not query as in your code.
In addition to that query type=service is not valid, it should be query type= service, (the space after the = is required).
However, I'm a little confused also by your command, I'm unsure whether you're wanting to know if there's an active service named bthserv, or if there's an active service with a name containing the case insensitive string bthserv.
If you're wanting to know if there's an active service named bthserv, you should really just query it by name, query bthserv. From there you can simply use && and || for successful and unsuccessful commands, (I've just used Echo commands below).
Example:
#%__AppDir__%sc.exe query bthserv 1> NUL && (Echo bthserv is an installed service) || Echo bthserv is not an installed service
Alternatively, you can use the ErrorLevel.
Example:
#%__AppDir__%sc.exe query bthserv 1> NUL
#If ErrorLevel 1 (Echo bthserv is not an installed service)Else Echo bthserv is an installed service
If you're wanting to know if there's an active service with a name containing the case insensitive string bthserv, (not matching it), then the find command is okay.
However, when you run that command within a for-loop, the = character is treated as a delimiter by the cmd.exe instance, the command is passed to. You'll therefore need to escape it, using the caret, ^. In addition to that, if you want the matched service name to be captured, you'll need to select everything after the first token, using the default       and TAB delimiters.
Example:
#For /F "Tokens=1,*" %%G In ('%__AppDir__%sc.exe query type^= service ^| %__AppDir__%find.exe /I "bthserv"') Do #Echo %%H
However, you could also enclose the entire string passed to the cmd.exe instance in doublequotes, and not need to escape anything.
Example:
#For /F "Tokens=1,*" %%G In ('"%__AppDir__%sc.exe query type= service | %__AppDir__%find.exe /I "bthserv""') Do #Echo %%H

How is it possible to get Windows default user profile path via CMD?

Windows default user profile is usually %SystemDrive%\users\default but its real location is not an environment variable but it can be useful to have it.
Default user profile path can be detected by system registry query like that
#echo off
for /f "tokens=2*" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\WINDOWS NT\CurrentVersion\ProfileList" /v "Default"') do set "defaultuserprofile=%%b"
echo %defaultuserprofile%
pause
But we get the value %SystemDrive%\Users\Default where %SystemDrive% is not converted to C: (or other letter) so environment variable %defaultuserprofile% can not be used as normal environment variable path for file operations.
Alternative variant can be something like
#echo off
cd /d "%public%"
cd ..\
set usersdir=%cd%
set defaultuserprofile=%usersdir%\default
echo %defaultuserprofile%
pause
But it seems to be not so good.
So how is it possible to get Windows default user profile path via CMD?
Don't your really want %PUBLIC%, which is C:\Users\Public? At least that's closest equivalent on Windows 10 to a "Default" folder.
#echo off
setlocal
set "defaultuserprofile="
for /f "tokens=1,2,*" %%A in ('reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" /v "Default"') do (
if "%%~A" == "Default" call set "defaultuserprofile=%%C"
)
echo "%defaultuserprofile%"
pause
The type of the data is REG_EXPAND_SZ. To expand the %SystemDrive% embedded in the string, use call set. call causes another parse of the command so that set assigns C:\ instead of %SystemDrive%.
Like the 2nd OP code, which is not as reliable as the reg query:
#echo off
cd /d "%Public%\..\Default" || exit /b 1
echo "%cd%"
pause
If you want to view the Default folder and other hidden folders in the Users directory, use:
dir /a:h
Output is the symlink named All Users, the folder named Default and the symlink named Default User on Windows 10 v1903.
Firstly, just to mention the purpose of the Default user profile is as the basis for all new user profiles. Therefore it should be used only to configure applications, settings and customizations for each future new user account on the PC. (modifications within it do not propagate to existing users).
The following method is similar to the existing answer, in that an additional expansion is used to cater for any variables within the contained data string. Please note that the value type of the data is by default REG_EXPAND_SZ, but it can also be of type REG_SZ, (the expand type is only necessary if the string contains a variable).
#Echo Off
Set "RKey=HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList"
Set "RVal=Default"
Set "ProfilePath="
For /F "Tokens=2*" %%G In (
'""%__APPDIR__%reg.exe" Query "%RKey%" /V "%RVal%" 2>NUL|"%__APPDIR__%find.exe" /I "%RVal%""'
)Do For /F "Tokens=*" %%I In ('Echo("%%~H"')Do Set "ProfilePath=%%~I"
If Not Defined ProfilePath Exit /B 1
Rem Your code using "%ProfilePath%" goes below here
Echo "%ProfilePath%" & Pause
I have Remarked a line with comment, which can be optionally omitted, and provided an example line below it for demonstration purposes, please modify that as necessary.
The code uses full paths for all external commands, (via a special variable, %__APPDIR__%, which will always point to their correct location). I have done that in order to remove any reliance on the content of the editable environment variables %PATH% and %PATHEXT%, (deliberate, or accidental, modification of those two environment variables could otherwise break the code).

dot net command: net use - How to only get Alphabet and pathname?

When I do a "net use" on my command prompt, it will display the following:
New connections will be remembered.
Status Local Remote Network
-------------------------------------------------------------------------------
OK W: \\hfs2\ATS\Novell Profile Backup\wk\one\two\three\four\five\six\seven\eight\nine\ten\eleven\twelve\thirteen
Microsoft Windows Network
OK X: \\hfs2\ATS\Novell Profile Backup\wk\one\two\three\four\five\six\seven\eight\nine\ten
Microsoft Windows Network
OK Y: \\hfs2\ATS\Novell Profile Backup
Microsoft Windows Network
Unavailable Z: \\hfs2\ATS Microsoft Windows Network
The command completed successfully.
How do I extract ONLY get the drive alphabet and pathname?
W:
\\hfs2\ATS\Novell Profile Backup\wk\one\two\three\four\five\six\seven\eight\nine\ten\eleven\twelve\thirteen
X:
\\hfs2\ATS\Novell Profile Backup\wk\one\two\three\four\five\six\seven\eight\nine\ten
Y:
\\hfs2\ATS\Novell Profile Backup
Z:
\\hfs2\ATS
EDIT
WMIC does not require administrator rights
It does require rights for what you are trying to do. You can't use it to do admin things if not an admin.
It also requires an administrator to run it once on a system to set it up.
From Help
User Account Control
Under UAC, accounts in the local Administrators group have two access tokens, one with standard user privileges and one with administrator privileges. Because of UAC access token filtering, a script is normally run under the standard user token, unless it is run "as an Administrator" in elevated privilege mode. Not all scripts required administrative privileges.
Scripts cannot determine programmatically whether they are running under a standard user security token or an Administrator token. The script may fail with an access denied error. If the script requires administrator privileges, then it must be run in the elevated mode. Access to WMI namespaces differs depending on whether the script is run in elevated mode. Some WMI operations, such as getting data or executing most methods, do not require that the account run as an administrator. For more information about default access permissions, see Access to WMI Namespaces and Executing Privileged Operations.
Wmic
The first time you run Wmic after system installation, it must be run from an elevated command prompt. The elevated mode may not be required for subsequent executions of Wmic unless the WMI operations require administrator privilege.
Use WMIC
wmic netuse get /format:list
gives you what's available.
Use something like
wmic netuse get remotepath, localname /format:list
To put the output in a file or on the clipboard.
WMIC specific switch
/output or /append
eg
wmic /node:"#%userprofile%\desktop\ComputerName.txt" /output:"%userprofile%\desktop\EventLog.html" /failfast:on PATH Win32_NTLogEvent where (EventIDentifier=42 or eventidentifier=1003) get /format:hform
(/node is a list of IP addresses and/or computer names of computers to run the command against, one IP address or computer name per line)
General Command Prompt File Redirection
Appending >filename.ext (or >>filename.ext to append to a file)to a command writes the output to the file rather than the screen.
wmic baseboard get product,Manufacturer,model,partnumber>MotherboardPartNum.txt
General Command Prompt Piping
Appending |command sends the output to a command rather than the screen. The usefull commands that output is sent to are
find or findstr (finds and filters text)
sort (sorts the output)
more (displays output to screen one page at a time)
clip (puts output onto the clipboard)
null (makes the data disappear for good - used for unwanted error messages)
wmic baseboard get product,Manufacturer,model,partnumber|clip
Combining Piping and Redirection
So we can combine them. To send the list to a file on the desktop in reversed sort order (z to a) with blank lines removed.
wmic service get name,displayname /format:list|findstr .|sort /r>"%userprofile%\desktop\services_reversed.txt"
WMIC Output Options
The output options are
/Format:list (a list - use notepad to view)
/format:table (a table - use notepad to view)
/format:hform (an html list - name the file's extension .html so IE will show)
/format:htable (an html table - name the file's extension .html so IE will show)
/format:csv (comma seperated variable - used for importing data into other programs such as excel)
also value, mof, rawxml, and xml.
So,
sort /?
find /?
findstr /?
more /?
clip /?
There are some problems in the output of net use
The Status field can hold information or be empty.
The Network field can have multiple values depending of network mapping. In my case i have "Microsoft Windows Network" and "Netware Services". So, there is no direct substitution.
The Network field can be in the same line that the Remote field or can be on the next line, and as the Remote field may include spaces, checking the character at the column limit position is not reliable. It is necessary to delay the check until the next line is readed to determine if it contains remote data.
So, not a one liner to handle it
#echo off
setlocal enableextensions disabledelayedexpansion
set "drive="
for /f "skip=6 tokens=1,* delims=\" %%a in ('net use') do (
if defined drive (
setlocal enabledelayedexpansion
if "%%b"=="" (
echo !drive! !networkPath!
) else (
echo !drive! !networkPath:~0,26!
)
endlocal
set "drive="
)
if not "%%b"=="" for /f "tokens=2" %%c in ("x%%a") do (
set "drive=%%c"
set "networkPath=\\%%b"
)
)
%%a loop will read the lines from net use and split them using a backslash as delimiter. This will allow us to determine if the line contains or not a network path (if there is no second token, the line did not contain a backslash).
As we are delaying the output of the information in one line until the next is readed (to determine if the remote path continues in the Network column), the first operation inside the for loop is to determine if we have data pending from previous loop. If there is data, depending on the content of the current line we select what to output.
Once the data is echoed, if the current line contains network information, it is saved for later output.
This is the faster solution, but there are two alternatives that require less code:
multiple net use commands
#echo off
setlocal enableextensions disabledelayedexpansion
rem For each line in the output of the net use that includes a drive letter
for /f "delims=" %%a in ('net use^|find ":"') do (
rem Retrieve the drive letter from the line
for /f "tokens=2" %%b in ("x%%a") do (
rem Run a net use with the drive letter and output the drive and the path
for /f "tokens=1,* delims=\" %%c in ('net use %%b') do if not "%%d"=="" echo(%%b \\%%d
)
)
Less code, but as multiple net use commands are executed, it is slower
Use WMIC
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "tokens=2,3 delims=," %%a in (
'wmic netuse get LocalName^, RemoteName^, Status /format:csv ^| find ":"'
) do echo(%%a %%b
Less code, but in this case, adminitrator righs are required to run the command
I might be a little late but this helped me
WMIC NETUSE GET LocalName, RemotePath /FORMAT:TABLE | FIND /i ":"

What would be the Windows batch equivalent for HTML's input type="password"?

I need to get authentication credentials from the users within a Windows script but the classic "first Google result" approach:
SET /P USR=Username:
SET /P PWD=Password:
is less than satisfying, so I was wondering if there's let's say an "equivalent" to HTML's input type="password"?
Any comment would be really appreciated, thanks much in advance!
check out this
http://www.netikka.net/tsneti/info/tscmd052.htm
#echo off & setlocal enableextensions
:: Build a Visual Basic Script
set vbs_=%temp%\tmp$$$.vbs
set skip=
findstr "'%skip%VBS" "%~f0" > "%vbs_%"
::
:: Prompting without linefeed as in Item #15
echo.|set /p="Password: "
:: Run the script with Microsoft Windows Script Host Version 5.6
for /f "tokens=* delims=" %%a in ('cscript //nologo "%vbs_%"') do set MyPass1=%%a
::
::echo.
echo.|set /p="Retype : "
for /f "tokens=* delims=" %%a in ('cscript //nologo "%vbs_%"') do set MyPass2=%%a
::
:: Clean up
for %%f in ("%vbs_%") do if exist %%f del %%f
::
:: Demonstrate the result
echo.
if "%MyPass1%"=="%MyPass2%" (
echo The entered password was %MyPass1%
) else (
echo No match)
endlocal & goto :EOF
'
'The Visual Basic Script
Set WshPass = WScript.CreateObject("ScriptPW.Password") 'VBS
Password=WshPass.GetPassWord() 'VBS
WScript.Echo PassWord 'VBS
By judicious use of another tool freely available on Windows, the following two scripts do the job you want.
First, GetPwd.cmd:
#echo off
:: GetPwd.cmd - Get password with no echo.
<nul: set /p passwd=Password:
for /f "delims=" %%i in ('cscript /nologo GetPwd.vbs') do set passwd=%%i
echo.
:: This bit's just to prove we have the password.
echo %passwd%
Then, GetPwd.vbs:
' GetPwd.vbs - Get password with no echo then echo it. '
Set oScriptPW = CreateObject("ScriptPW.Password")
strPassword = oScriptPW.GetPassword()
Wscript.StdOut.WriteLine strPassword
Explanation:
GetPwd.vbs simply uses the password object to input the password from the user and then print it to standard output (next paragraph will explain why that doesn't show up in the terminal).
GetPwd.cmd is a bit trickier (but command scripts usually are).
The "<nul: set /p passwd=Password: " command simply outputs the prompt with no trailing CR/LF - it's a sneaky way to emulate bash's "echo -n". It sets passwd to an empty string as a side effect and doesn't wait for input since it's taking its input from the nul: device.
The "for /f "delims=" %%i in ('cscript /nologo GetPwd.vbs') do set passwd=%%i" statement is the trickiest bit. It runs the vbscript with no Microsoft advertising (/nologo), so that the only line output is the password (from the vbscript "Wscript.StdOut.WriteLine strPassword".
Setting the delimiters to nothing is required to capture input lines with spaces, otherwise you just get the first word. The "for ... do set ..." sets passwd to be the actual password output from the vbscript.
Then we echo a blank line (actually terminate the "Password: " line) and echo the password so you can verify it works:
C:\Pax> GetPwd
Password:
this is my password
C:\Pax>
The scriptpw.dll is available with XP and 2K3 but not necessarily later versions.
Instructions for Vista and presumably Win7 are below, give them a try:
To mask the password, the script takes advantage of the ScriptPW COM object. ScriptPW is loaded by default on Windows XP and Windows 2003. If you’re running Windows 2000 or Windows Vista, you will need to copy the scriptpw.dll file from the Windows\System32 folder of an XP system, or Windows 2003 system to the Winnt\System32 or Windows\System32 folder on your Windows 2000 or Vista system. Once the DLL has been copied, you will need to register it by running the command:
regsvr32 scriptpw.dll
To successfully register the DLL on a Vista machine, you will need to open the command prompt as administrator. To do this, click Start | All Programs | Accessories. Then right-click on the Command Prompt shortcut and select “Run as administrator.” Once at the command prompt as administrator, you’ll be able to successfully run the regsvr32 scriptpw.dll command to register the DLL.
1.Pure batch solution that (ab)uses XCOPY command and its /P /L switches found here :
:: 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
2.Password submitter that uses a HTA pop-up
. This is a hybrit .bat/jscript/mshta file and should be saved as a .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' >
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'></input>
<hr>
<button onclick='pipePass()'>Submit</button>
</body>
</html>
3.A self-compiled .net hybrid .Again should be saved as .bat .In difference with other solutions it will create/compile a small .exe file that will be called (if you wish you can delete it). Also requires installed .net framework but that's rather not a problem:
#if (#X)==(#Y) #end /* JScript comment
#echo off
setlocal
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("*");
}
} while (key.Key != ConsoleKey.Enter);
Console.Error.WriteLine();
Console.WriteLine(pwd);
I assume that you want no echo of the password on the screen.
If a pop-up window is ok for you, you could use e.g. VBScript to show an IE window displaying a password field. Here's an example.
As an alternative you could call your script from an HTA (HTML Application) file (see Introduction to HTML Applications (HTAs).
Regards,
divo
If you can install Cygwin, you'll get a bash shell by default, so this command will work:
read -s -p "Password: " PASSWORD
Only problem is now the value of PASSWORD is only set in the bash shell, not as an environment variable a batch file can see (don't use PWD as this means something else in cygwin). So you would have to rewrite your script as a bash shell script (maybe not too hard given the limitations of the command prompt!).
Or you could pass the password into a batch script from cygwin, but this means running a new instance of the command prompt:
cmd /cyourbatchfile.bat $PASSWORD
All a bit convoluted and not at all satisfying ;)
We do stuff like this all the time but put the password in the commandline and pass it to a variable in the batch file.
Another approach is to call PowerShell commands from your Batch script. Here's an example that configures the logon account of a service:
$password = Read-Host "Enter password" -AsSecureString;
$decodedpassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password));
& "sc.exe" config THE_SERVICE_NAME obj= THE_ACCOUNT password= $decodedPassword;
where THE_SERVICE_NAME is the name of the service to configure and THE_ACCOUNT is the logon account.
Then we can use it from a batch script like that:
call powershell -Command "$password = Read-Host "Enter password" -AsSecureString; $decodedpassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)); & "sc.exe" config THE_SERVICE_NAME obj= THE_ACCOUNT password= $decodedPassword;"
which is simply calling PowerShell.exe and passing the three commands.
The advantage of this approach is that the majority of Windows installations today include PowerShell, so no extra program or script is needed. The drawback is that you will need to either use the password inside the PowerShell call (like in my example) or store it in an environment variable and then use it from your batch script. I preffer the former because it is more secure and simpler.
You may use ReadFormattedLine subroutine for all kind of formatted input. For example, the commands below read an username and password of 8 characters each, display asterisks in the screen, and continue automatically with no need to press Enter:
call :ReadFormattedLine USR="********" /M "Username: "
call :ReadFormattedLine PWD="********" /M "Password: "
Or in a different way:
call :ReadFormattedLine nameAndPass="******** / ********" /M "Enter Username / Password: "
In previous example, when the user completed the username, the subroutine display the slash and read the password; if the user delete characters, the slash is also deleted automatically.
This subroutine is written in pure Batch so it does not require any additional program, and it allows several formatted input operations, like read just numbers, convert letters to uppercase, etc. You may download ReadFormattedLine subroutine from Read a line with specific format.
ConSet is a free tool written by Frank P. Westlake. It is an extended version of standard Windows command set.
ConSet.exe - Displays, sets, or deletes cmd.exe environment variables, modifies console parameters, and performs floating point mathematics.
As it is not a standard Windows console application, the usage of this tool requires either the distribution of this tool together with the batch file or the tool is stored on a server share and the batch file calls this tool directly from the server share.
ConSet makes a prompt for a password string with hidden input assigned to an environment variable very easy:
ConSet.exe /PH "PWD=Password: "
The additional parameter H results in hiding user input.
I wrote an open-source tool called editenv that replaces my older editv32/editv64 utilities:
https://github.com/Bill-Stewart/editenv
It provides the --maskinput (-m) option[*] that lets you hide the typed input. Example:
editenv --maskinput --prompt="Password: " PWD
This command displays a Password: prompt, and whatever you enter is placed in the PWD environment variable.
Download here:
https://github.com/Bill-Stewart/editenv/releases
[*] Note that the --maskinput (-m) option is not secure -- typed input is placed in plain-text in the environment. This feature is for convenience only.
Original poster asked for a DOS BATCH solution that allows for input of a password without printing it on the screen. All solutions so far use some external script, VBA, Powershell, Cygwin, whatever. To me, none of these are a nice, clean and simple.
In my case, I will go the python route. A DOS BAT script can easily be replaced by a simple python script. In python, the password entry problem is trivially solved with import getpass; password = getpass.getpass() . Then, python is a lightweight and reliable extension to your windows pc, and the script may be portable to other OS's (linux, mac). In my case, I need a startup script for Pentaho, a tool that is available for windows and linux.
This issue makes you wonder why write scripts in BAT or even BASH. Is powershell really an improvement on BAT, and does python perhaps solve problems in all of these systems?
This also makes you wonder how Powershell could miss the boat here. Why is the python call not also in Powershell, there is no licensing issue??? The "not invented here" syndrome?
Of course, there will be very simple situations where a BAT (or BASH) script is the easiest way, or where Powershell is required, but otherwise I'd go for python.

Resources