Here's another option that denies unrecognized switches, accepts both /
and -
as valid switch prefixes, performs case-insensitive switch checking, and pings remotehost to check for validity.
@echo off
setlocal enabledelayedexpansion
if not "%~1"=="" goto :switches
:usage
echo Usage: %~nx0 [/X] [/L loginname] remotehost
goto :EOF
:switches
rem // make sure variables are undefined
for %%I in (forward login host switch valid) do set "%%I="
rem // loop through all arguments
for %%I in (%*) do (
rem // if this iteration is a value for the preceding switch
if defined switch (
rem // if that switch was -L or /L (case-insensitive)
if /i "!switch:~1!"=="L" set "login=%%~I"
rem // clear switch variable
set "switch="
) else (
rem // if this iteration is a switch
echo(%%~I | >NUL findstr "^[-/]" && (
set "switch=%%~I"
rem // if this is a valid switch
for %%x in (X L) do (
if /i "!switch:~1!"=="%%x" set "valid=true"
)
if not defined valid (
echo Unrecognized switch: %%~I
goto usage
)
set "valid="
if /i "!switch:~1!"=="X" (
set "forward=true"
set "switch="
)
) || (
rem // not a switch. Must be a host.
ping -n 1 %%~I | findstr /i "^Reply.*time.*[0-9]" >NUL && (
set "host=%%~I"
) || (
echo Host %%~I is unreachable.
)
)
)
)
if not defined host goto usage
<NUL set /P "=Args passed: "
if defined forward <NUL set /P "=FORWARD "
if defined login <NUL set /P "=LOGIN %login% "
echo %host%
And you know, if you're not comfortable scripting Windows Batch scripts, you might consider another scripting language. Many will suggest PowerShell, and it is a worthwhile choice. But if you'd rather not learn an entire new language and format, if you're familiar with JavaScript, JScript is very similar. I'll demonstrate, and I hope you'll be able to see the similarities. Save this with a .js extension. To run it, do cscript /nologo scriptname.js switches here
:
// convert WSH.Arguments object to a JS array
for (var args=[], i=0; i<WSH.Arguments.Length; i++)
args.push(WSH.Arguments(i));
function error(txt, code) {
WSH.StdErr.WriteLine(txt);
WSH.StdErr.WriteLine('Usage: '+WSH.ScriptName+' [/X] [/L loginname] remotehost');
WSH.Quit(code);
}
for (var i=0; i<args.length; i++) {
switch (args[i].toLowerCase().replace("-","/")) {
case "/x":
var forward = true;
break;
case "/l":
if (++i == args.length || /^\//.test(args[i]))
error('Invalid login name.', 1);
else var login = args[i];
break;
default:
if (/^\//.test(args[i]))
error('Unrecognized option: ' + args[i], 2);
else var host = args[i];
}
}
if (!host) error('No host specified.', 3);
WSH.Echo([
'Command: ',
(forward ? 'FORWARD ' : ''),
(login ? 'LOGIN ' + login + ' ' : ''),
host
].join(''));
JScript and JavaScript have lots in common. You can invoke the same RegExp object methods and Array object methods, modify prototypes, coerce data into compatible data types or test their truthiness, and so on. JScript is JavaScript, just with a root ancestor object of "WScript" (or "WSH" for the lazy) instead of "Window".
// convert WSH.Arguments proprietary object to a JS array
for (var args=[], i=0; i<WSH.Arguments.Length; i++)
args.push(WSH.Arguments(i));
function error(txt, code) {
WSH.StdErr.WriteLine(txt);
WSH.StdErr.WriteLine('Usage: '+WSH.ScriptName+' [/X] [/L loginname] remotehost');
WSH.Quit(code);
}
// returns idx of array element matching rxp (or -1 if no match)
Array.prototype.match = function(rxp) {
for (var i=this.length; i--;) if (rxp.test(this[i])) return i;
return -1;
}
var X = args.match(/^[/-]X$/i);
if (X > -1) var forward = args.splice(X, 1)[0];
var L = args.match(/^[/-]L$/i);
if (L > -1) var login = args.splice(L, 2)[1];
for (var invalid=[], i=args.length; i--;)
if (/^[/-]/.test(args[i])) invalid.push(args[i]);
if (invalid.length) error('Unrecognized option: ' + invalid.join(), 1);
if (!args.length) error('No host specified.', 2);
WSH.Echo([
'Params: ',
(forward ? 'FORWARD ' : ''),
(login ? 'LOGIN ' + login + ' ' : ''),
args[0]
].join(''));
And if you want to use these arguments to launch an external program, look into objShell.Run
.
If you want to deploy your script to other users, making it into a Batch + JScript hybrid format and saving it with a .bat extension makes it more user-friendly to execute. Just put this at the top of either of those solutions above, and save the script with a .bat extension.
@If (@CodeSection == @Batch) @then
@echo off & setlocal
cscript /nologo /e:JScript "%~f0" %*
goto :EOF
@end // end Batch / begin JScript hybrid chimera
// JScript code here
The way it works is that, first, the script loads with the cmd batch interpreter. Since (@CodeSection
does not equal @Batch)
, the rest of the line is never attempted. Continue until the cscript
line, which reloads this script using the JScript interpreter, passing the command line arguments along.
JScript determines that @CodeSection
in fact does not equal @Batch
, and skips to @end
. At the end of the JScript execution, cscript.exe
exits and the Batch thread resumes until goto :EOF
or exit /b
.
With the hybrid code added, now the syntax is scriptname.bat arguments here
. If you want to bypass the batch code and execute only the JScript portion, cscript /nologo /e:JScript scriptname.bat argumentss here
also works.