I'm putting together a very basic automation script using the windows batch operation in which will loop through a list of IP addresses and run a plink command to logon and keep alive the account on the server because it has recently logged onto the server.
I believe I have most of the function working however I am having an issue with passing through the password. I'm seeing an issue where if the password I have has special characters and in which I run the script through command prompt it does not pass through the special character to the plink command. Here is a look of the script:
#echo on
SET userid=root
SET passwd=Welcome1%
for /f "delims=" %%i in ('type "ipaddress.txt" ') do (
pushd "C:\Program Files (x86)\PuTTY"
plink.exe -pw %passwd% %userid%#%%i hostname
popd
)
The ipaddress.txt file contains:
10.0.0.1
10.0.0.2
10.0.0.3
The idea is to go through the list for each IP address, logon and validate access. I'm also looking to ensure the value Y or N is passed to make sure a server is trusted or not as part of the script. Any help would be greatly appreciated.
You could see your script behaviour with #echo on (run it from within a cmd window instead of double-clicking). You are right that some special characters need to be escaped. If your password should be Welcome1% literally then use
SET passwd=Welcome1%%
or advanced set command syntax
SET "passwd=Welcome1%%"
Edit. Above advice covers particularly % percentage sign in a string. However, escaping some characters with special meaning (e.g. redirectors <, >, |, & etc.) as ^<, ^>, ^|, ^& seems to be a bit inconvenient and could not suffice. Therefore required advanced set command syntax and delayed expansion enabled instead.
For instance, Wel<come>1% string could be used as follows:
SET "userid=root"
SET "passwd=Wel<come>1%%"
for /f "delims=" %%i in ('type "ipaddress.txt" ') do (
pushd "C:\Program Files (x86)\PuTTY"
SETLOCAL EnableDelayedExpansion
plink.exe -pw !passwd! %userid%#%%i hostname
ENDLOCAL
popd
)
I'm currently working in an organization that has migrated their OU groups so that everything belongs to a parent folder called "users and workstations".
This is a slight problem for me, as I have a few batch scripts that delete users and computers from a text file - something that I run fairly regularly.
The current code I use, for example, to disable a batch of machines is below
#echo off
CLS
ECHO Now Disabling Machines...
TIMEOUT 2 > nul
Pause
FOR /f %%i in (%~dp0\computernames.txt) do (
dsquery computer -name %%i | dsmod computer -disabled Yes
)
If I run this code since the change, I get the following error
dsmod failed:'Target object for this command' is missing.
type dsmod /? for help.
However, if I manually type the dsquery / dsmod line of code into command prompt and replace the "%%i" with a computer that failed, it succeeds.
I'm almost certain that this is due to the spaces within the OU folder structures, but don't know what to do to change my script to continue working.
Is there a way to change it? should I try something else? I'm going crazy trying to figure this out!!!
Thanks in advance,
Ben
P.S. I've come up with a solution that seems to work - I'll keep this open incase anyone can suggest a better way to do what i need to do. Please see below for the code that works for me. Looks like I needed to add correct delims and two sets of double-quotes to exit out correctly.... it doesn't make too much sense to me... but it works...
#echo off
setlocal disabledelayedexpansion
CLS
ECHO Now Disabling Machines...
ECHO.
Pause
FOR /f "delims= " %%i in (%~dp0\computernames.txt) do (
echo disabling %%i && echo. && dsquery computer -name ""%%i"" | dsmod computer -disabled Yes && echo.
)
Try using quotes on %%i in this line like this
dsquery computer -name "%%i" | dsmod computer -disabled Yes
Edit (added below):
Ahhhh... I bet the current directory is not what you think. Perhaps you are executing from a UNC drive. Try this:
pushd %~dp0
FOR /f %%i in (computernames.txt) do (
dsquery computer -name "%%i" | dsmod computer -disabled Yes
)
Please see original post for solution.
disabling delayed expansion and specifying the delims, along with double double quoting the variable seems to have fixed the problem!
My question, is extremely similar to the following SO question: How to get Java Version from batch script?
In fact, it did almost solve my problem. The only difference is that I've to check the Java version based on %JAVA_HOME%, which the user is free to modify. The issue that I'm facing is with this code:
#ECHO OFF
SETLOCAL enableextensions enabledelayedexpansion
IF "%JAVA_HOME%"=="" (
#ECHO Please set JAVA_HOME environment variable
EXIT /B
)
#echo "%JAVA_HOME%"
REM Checking JAVA_VERSION
SET JAVA_VERSION=
FOR /f "tokens=3" %%g in ('"%JAVA_HOME%"\bin\java -version 2^>^&1 ^| findstr /i "version"') do (
SET "JAVA_VERSION=%%g"
)
%JAVA_HOME%% in my system points to "C:\Program Files\jdk1.7.0_25" (notice the space in the path)
Even with the quotes, I get the following error in command line:
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
Any idea as to how to solve this problem? (The comments to the aforementioned article also mentions this issue). I'm working on a Windows 7 machine
FOR /f "tokens=3" %%g in ('"%JAVA_HOME%\bin\java" -version 2^>^&1 ^| findstr /i "version"') do (
SET "JAVA_VERSION=%%g"
)
Edit the %JAVA_HOME% Variable into:
C:\"Program Files"\jdk1.7.0_25
if you want it automated, type
set %JAVA_HOME%=C:\"Program Files"\jdk1.7.0_25
REASON WHY:
The batch file does not accept the quotes; It is identifying them as a single file. So it attempts to find "C:\Program Files\jdk1.7.0_25" NOT as a folder path, but as a folder NAME in your root folder. If you type in
C:\"Program Files"\jdk1.7.0.25 it identifies that "Program Files" is a single file. If there are no redirection operators, It would think that the path would be like this;
C:\Program\Files\jdk1.7.0_25. It worked for me; It should probably work for you.
Hope that helped
-SonorousTwo
I had a similar problem, take a look at my QA: How to get Java version in a batch script subroutine?
From my answer:
It seems that piping the output to findstr was stripping the quotes for some reason.
I managed to fix the problem without Epic_Tonic's workaround (which would be very difficult to do with a path as a parameter).
This should work in your case:
set first=1
for /f "tokens=3" %%g in ('"%JAVA_HOME%\bin\java" -version 2^>^&1') do (
if !first!==1 echo %%~g
set first=0
)
Note: first is for only searching the first line of java -version's output (reference).
I am launching a browser from batch file.
START "www.google.com"
I would like to know the PID of this browser window launched.
There can be many browser windows launched on a single machine. I need to find the PID of the process which was launched by my batch file only. I tried with WINDOWTITLE filter. But its not a good idea as titles may change in future. I am using Windows XP/7
Any help would be appreciated.
Thanks.
For what it worth (question is more than 2 years old) this code do the trick, just change variable according to default browser exe
set "browser=palemoon.exe"
tasklist /FI "imagename eq %browser%" /NH /FO csv > task-before.txt
start www.google.com
tasklist /FI "imagename eq %browser%" /NH /FO csv > task-after.txt
:: fc /L /LB1 test4-Before.txt test4-After.txt | find /I "%browser%"
for /f "delims=, tokens=2,*" %%A in ('"fc /L /LB1 task-before.txt task-after.txt | find /I "%browser%""') do set pid=%%A
SETLOCAL enabledelayedexpansion
pid=!pid:"=!
ENDLOCAL
echo pid is %pid%
This is just an idea, to get you maybe on the way
there is a command called Tasklist
there is a switch called filter /FI with lets you decide what filter parameters you want to output, f.e PID. Output this to a > 1.TXT
start your proces
recheck the watchlist and output to 2.TXT
Then you would have to get creative. COmpare 1 to 2,
maybe remove the processes in 1 from the 2.TXT
The remainig PID is what you wanted?
If you have some programming experience, you could create your own console application that accepts command-line parameters and passes them to the Win32 API CreateProcess() function. One of its output values is the spawned process ID, which your app could then return. Then just update your batch file to call your app instead of using START directly.
I'm trying to do the same thing. Though there must be some way of doing it, but all my Googling suggests not.
Check out robvanderwoude.com to see a list of 3rd party tools and examples. Also check out the full list of Sysinternal's process utilities here.
I've been looking at this for about 2 hours now and I think that there is a way to do this, but it requires some more insight on how windows handles iexplore.exe for PID...
I have a working version of a batch file I wrote that will get you what you want, BUT only if its the FIRST AND ONLY Internet Explorer Window open.
For some reason I can't get the PID to change when I open new browsers, but I can get results if there is no window open (obviously because there is no PID)
Anyhow, this is what I have... you should be able to run this on your system and it will tell you that there are no differences and it might actually produce results if your default browser is Firefox or Chrome or something... just need to make the changes to what I'm providing.
#echo off
IF EXIST c:\temp\pshell.txt del c:\temp\pshell.txt
IF EXIST C:\temp\PID1.txt del C:\temp\PID1.txt
IF EXIST C:\temp\PID2.txt del C:\temp\PID2.txt
IF EXIST C:\temp\PowerFormat.txt del C:\temp\PowerFormat.txt
powershell.exe Get-Process iexplore>C:\temp\pshell.txt
FOR /F "skip=3 tokens=7 delims= " %%1 IN ( c:\temp\pshell.txt ) DO #echo %%1>> C:\temp\PID1.txt
start "title" "www.google.com"
powershell.exe Get-Process iexplore>C:\temp\pshell.txt
FOR /F "skip=3 tokens=7 delims= " %%2 IN ( c:\temp\pshell.txt ) DO #echo %%2>> C:\temp\PID2.txt
FC /L c:\temp\pid1.txt c:\temp\pid2.txt> C:\temp\FileComparison.txt
FOR /F "tokens=7 delims=" %%3 IN (c:\temp\FileComparison.txt) DO #echo %%3>C:\temp\DiffPID.txt
FINDSTR "FC: no differences encountered" c:\temp\FileComparison.txt
IF '%ERRORLEVEL%'=='0' del C:\temp\FileComparison.txt & echo.No PID Found
IF NOT '%ERRORLEVEL%'=='0' type c:\temp\FileComparison.txt
pause
exit
Let me know if this helps...
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.