Running Plink in a Windows Batch - Issues - windows

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
)

Related

CMD Fileless equivalent of < redirection

I have a batch that wraps AnyConnect Mobility Client CLI (vpncli.exe) and asks username and password to later handle them to vpncli.
Simplified code:
set /p user_id=Username:
set /p pwd=Password:
echo %user_id%> c:\temp\configvpn.txt
echo %pwd%>> c:\temp\configvpn.txt
set install_dir="C:\Program Files (x86)\Cisco\Cisco AnyConnect Secure Mobility Client"
%install_dir%\vpncli.exe connect myvpn.mydomain.TLD -s < c:\temp\configvpn.txt
net use h: \\fileserver\sharename /user:domain\%user_id% %pwd%
The last line it's why we do it this way: to not prompt user password twice (first for connecting VPN and second to map network drive)
For security reasons I'm improving the script to not write password to disk. I need a fileless equivalent of this "< c:\temp\configvpn.txt"
I tried :
(
#echo %user_id%
#echo %pwd%
) | %install_dir%\vpncli.exe connect myvpn.mydomain.TLD -s
Not success so far. The output is this loop:
>> Please enter your username and password.
Group: VPN-TESTGROUP
Username: [myUsername] Password:
>> Login failed.
Group: VPN-TESTGROUP
Username: [myUsername] Password:
>> Login failed.
(repeats indefinitely)
Is there a way to do this?
It's probably a problem of the piped block, as there are spaces added at the end of each command.
This code avoids the spaces and should solve your problem
(SET LF=^
%=empty=%
)
(
echo %user_id%%%LF%%rem.
echo %pwd%%%LF%%rem.
) | %install_dir%\vpncli.exe connect myvpn.mydomain.TLD -s
But you should test it without any special characters in you user_id or password!
As you already find out, the problems is trailing spaces inside the pipe, And as you can see in jeb's answer getting ride of the trailing spaces requires special handling.
One aspect of pipes that leads to confusion is that the piped commands are not executed in batch file context with batch syntax rules, but they are executed in command line context with command line syntax rules in a child cmd instance.
One needs to thoroughly understand the mechanics of the CMD/Batch pipes to be able to construct and maintain a working solution this way, and it is not a straightforward task for slightly more complex piped blocks.
Here is an alternate way which enables piping of any complex blocks of commands with the same level of flexibility as you have in normal batch codes.
#echo off
if "%~1"=="/LPipe" goto :/LPipe
if "%~1"=="/RPipe" goto :/RPipe
set /p user_id=Username:
set /p pwd=Password:
"%~f0" /LPipe | "%~f0" /RPipe
exit /b
:/LPipe
REM This will be executed inside a pipe but in batch context
REM Enable delayed expansion to be able to send any special characters
setlocal EnableDelayedExpansion
REM It's easy to take care of trailing spaces, no special hacks needed.
echo !user_id!
echo !pwd!
goto :EOF
:/RPipe
REM This will be executed inside a pipe but in batch context
%install_dir%\vpncli.exe connect myvpn.mydomain.TLD -s
goto :EOF

Windows: How to programatically connect to wireless networks?

With Windows 10 is it possible to setup up known networks and be able to connect to them without all the mouse movement and click?
Using Windows batch files, you can set it up to connect to networks you already know (Network1 or Network2, below) without ever touching the mouse.
#echo off
setlocal EnableDelayedExpansion
for %%i in ("Network1"
"Network2") do (
netsh wlan show networks mode=ssid | findstr /C:%%i
if !ERRORLEVEL! EQU 0 (
echo "Found %%~i - connecting..."
netsh wlan connect name=%%i
exit /b
) else (
echo "Did not find %%~i"
)
)
#echo on
Save the above to .bat and run it from cmd.exe or a program like Listary.
Some comments about the code:
If more than one of your listed networks are available, it will connect to whichever is first in the for loop list. You could also put the list in a file and change for %%i to for /F %%i
EnableDelayedExpansion and "!" around ERRORLEVEL
are needed to keep the variable ERRORLEVEL from being assigned
whatever it was at the beginning of the script. Since I don't
normally program Windows batch files, this is 2 hours of my life
gone that you won't have to deal with.
All the echoing is for debugging; the echo off at the top squelches it.
%% needed for variables in Windows batch files. The variable is referenced with % at the command line.
%%~i strips the quotation marks around the string when outputting to stdout.

windows cmd enabledelayedexpansion not working

I'm having trouble running !var! examples ad described here http://ss64.com/nt/delayedexpansion.html
Instead of the expected variable content output as the example describes, I get the literal "bang V A R bang" output, any idea?
C:\>Setlocal EnableDelayedExpansion
C:\>Set _var=first
C:\>Set _var=second& Echo %_var% !_var!
first !_var!
thanks.
You are getting an unexpected result because you are issuing the commands at the command prompt. Create a batch file by putting the following commands in a file with a .bat extension then run the batch file.
#echo off
Setlocal EnableDelayedExpansion
Set _var=first
Set _var=second& Echo %_var% !_var!
E.g., if I created a batch file named delayedexp.bat with the above contents, I would see the following when I run it:
C:\Users\JDoe\Documents\>delayedexp
first second
setlocal only works within the confines of a command script:
help setlocal
If you have access to the parameters of the cmd call, you can set parameter /v. Must be first. And use ! instead % for variables.
%windir%\system32\cmd.exe /v /c set a=10&echo a=!a!&echo My Path is %CD%&pause
This is how, for example, you can get the date in the Russia-France format directly in the Windows shortcut, where a simple percentage is impossible due to its doubling. In std queries with the /v parameter, both a percentage and an exclamation mark will work fine, but single % for cicles.
%windir%\system32\cmd.exe /v /c echo off&for /F "tokens=1-6 delims=:., " %A In ("!date! !time!") Do (Echo %A.%B.%C %D:%E:%F)&pause

Batch script, call cmd on servers

I am trying to call x.cmd from many servers in a list and basically x.cmd will return a log file so I will copy the output log files into a new folder.
the structure in that list is:
server name&folder path of the x.cmd on thet server&output folder name that I will create
when I run the script below, it doesn't return any error and return value is 0. but x.cmd just doesn't do anything when I check on the actual server. x.cmd working fine once I run it manually.
Please if possible point me out the mistake of my script. my other concern is the folder path being too long(but it is within the limits of Microsoft if I am right). :) Thanks for your time.
#echo on
cd /d %~dp0
setlocal EnableDelayedExpansion
set serverList=List.txt
for /f "usebackq tokens=1,2,3* delims=&" %%A in ("%serverList%") DO (
set remoteCmd=x.cmd
wmic /node:%%A process call create "%%B\remoteCmd"
pause
robocopy %%B\logs Output\%%C /e
)
endlocal
Pause
JS
The problem seems to be that you're not actually calling x.cmd on the remote servers, since the variable isn't substituted in the wmic call. Move the definition of remoteCmd out of the loop and enclose remoteCmd in the wmic call in percent signs:
set serverList=List.txt
set remoteCmd=x.cmd
for /f "usebackq tokens=1,2,3* delims=&" %%A in ("%serverList%") DO (
wmic /node:%%A process call create "%%B\%remoteCmd%"
pause
robocopy %%B\logs Output\%%C /e
)
Update 1: Since you're getting a response on the shell with a processID and Error level=0, it's fairly safe to say that x.cmd was in fact started on the remote server. The fact that the logfile does not turn up in the same directory where x.cmd resides in, is very probably because the logfile is not given an absolute path in x.cmd. That means it will be created in the directory on the remote machine where the cmd.exe is located, which is executing x.cmd. In most systems this will be %WINDIR%\system32, i.e. c:\windows\system32.
Update 2: If modifying x.cmd is no option, then you need to change the path to it's directory before calling it. You can do it like this:
wmic /node:%%A process call create "cmd /c cd /d %%B & x.cmd"
Note: The cd /d allows you to change directories even across different drives.
Update 3: Since there are spaces in the directory names you'll need to enclose them with quotes - which will have to be escaped, since there already outer quotes enclosing the whole remote command. So that means:
wmic /node:%%A process call create "cmd /c \"cd /d %%B\" & x.cmd"
Note: A possible alternative to the inner quotes would be to use 8.3-filenames of the involved directories. You can view those with dir /x on the command line.

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