2

I use RDP on many different windows machines, and sometimes have to RDP into one, then rdp from there onto another.

I'd like to know if it is possible to create a Batch File that can read the Names of all Directories within a set path, then display them as numbered variables like a menu. After i input my selection, it would do the same for all .rdp files in the selected directory.

Below is an example of how i could manually hardcode it for each file...but I need something that will adapt to dropping an new rdp file into a directory rather than having to manually add it each time inside the batch file, as the number of sites/pcs and names can change regularly.

:site
ECHO Location List
ECHO.
ECHO 1 NSW
ECHO 2 QLD
ECHO.
SET /p site=Enter Selection: 
IF "%site%"=="1" GOTO NSW
IF "%site%"=="2" GOTO QLD    

:NSW
SET dirname=C:\Machine\NSW\
ECHO Machine List
ECHO.
ECHO 1 Client01.rdp
ECHO 2 Server01.rdp
ECHO 3 Server02.rdp
ECHO.
SET /p machine0=Enter Selection: 
IF "%machine0%"=="1" SET machine1=%dirname%Client01.rdp
IF "%machine0%"=="2" SET machine1=%dirname%Server01.rdp
IF "%machine0%"=="3" SET machine1=%dirname%Server02.rdp
GOTO connection

:connection
mstsc %machine1% /console

I've found several questions similar to this (such as here and here) but they all seem to be about just displaying a list and not getting them into a menu like option, also i still do not fully understand how the FOR command works.

Example of the directory structure.

C:\Batchfile.bat
C:\Machines\NSW\Client01.rdp
C:\Machines\NSW\Server01.rdp
C:\Machines\NSW\Server02.rdp
C:\Machines\QLD\Client01.rdp
C:\Machines\QLD\Client02.rdp
C:\Machines\QLD\Server01.rdp

The base directory would be set to C:\Machines then batch would store each sub-directory name to a numbered variable and echo them to the screen and prompt for selection.

Location List

1 NSW
2 QLD

Enter Selection:_

If user input 1 then then it would store each .RDP filename inside the QLD sub-directory to a numbered variable and echo them to the screen and prompt for selection.

Machine List for NSW

1 Client01.rdp
2 Server01.rdp
3 Server02.rdp

Enter Selection:_

After the user makes a selection at this point i would like to use the selected .rdp file with the mstsc command to launch an rdp session to the selected computer then loop back the beginning to allow to open a second connection at the same time.

I'd appreciate any help you could give.

Durry42
  • 401
  • 3
  • 10

2 Answers2

2

Here is one way:

@echo off
setlocal enabledelayedexpansion

:Start
ECHO Location List
ECHO.
ECHO NSW
ECHO QLD
ECHO.
SET /p site=Enter Selection: 

for /f %%a in ('dir /b/s "c:\Temp\%site%\*.rdp"') do (
  set /a i+=1
  echo !i! - %%~nxa
  set mach[!i!]=%%~nxa
)
set /p m0=Enter Selection: 
echo mstsc !mach[%m0%]! /console
set /p sel=Would you like to launch another [y/n]? 
if /i "%sel%" EQU "y" Goto :start

Or

@echo off
setlocal enabledelayedexpansion

:Start 
ECHO Location List
ECHO.
ECHO 1 - NSW
ECHO 2 - QLD
ECHO.
SET /p site=Enter Selection: 

set i=0 & set a=0
set site[1]=NSW
set site[2]=QLD

for /f %%a in ('dir /b/s "c:\Temp\!site[%site%]!\*.rdp"') do (
  set /a i+=1
  echo !i! - %%~nxa
  set mach[!i!]=%%~nxa
)
set /p m0=Enter Selection: 
echo mstsc !mach[%m0%]! /console
set /p sel=Would you like to launch another [y/n]? 
if /i "%sel%" EQU "y" Goto :start

Also, this is assuming all of your servers are 2003. Starting with 2008, I believe /console has been deprecated in lieu of /admin. If that's the case, it's easy enough to add a little more logic depending on which version of Server you're connecting to.

Matt Williamson
  • 6,947
  • 1
  • 23
  • 36
2
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION 
FOR /f "delims==" %%i IN ('SET s_ 2^>nul') DO SET "%%i="
SET "sourcedir=c:\sourcedir"
FOR /f "delims=" %%a IN ('dir/s/b/a-d "%sourcedir%\*.rdp"') DO (
 SET s_=%%~dpa
 FOR /f %%b IN ("!s_:~0,-1!") DO SET s_#%%~nb=Y&SET s_@%%~nb_%%~na=Y
)
CALL :showmenu "Location List" #
IF /i "%s_%"=="q" GOTO :EOF
SET s_site=%s_%
CALL :showmenu "Machine List for %s_site%" @ %s_site%
IF /i "%s_%"=="q" GOTO :EOF
SET s_machine=%s_%
ECHO(==============
ECHO site=%s_site% machine=%s_machine%
GOTO :EOF

:showmenu
SET s_items=1
CLS
ECHO(%~1
ECHO(
FOR /f "tokens=2,3delims=_%2=" %%i IN ('set s_%2') DO (
 IF "%3"=="" (
  CALL :showline %%i
 ) ELSE (
  IF "%3"=="%%i" CALL :showline %%j
 )
)

ECHO(
SET "s_="
SET /p "s_=Enter Selection : "
IF NOT DEFINED s_ SET s_=Q
IF /i "%s_%"=="q" GOTO :EOF
IF DEFINED s_%s_% CALL SET s_=%%s_%s_%%%&GOTO :EOF 
GOTO showmenu

:showline
SET "s_= %s_items%. "
ECHO %s_:~-4%%1
SET s_%s_items%=%1
SET /a s_items+=1
SET "s_%s_items%="
GOTO :eof

This way is self-adjusting. Unfortunately it also uses a few hieroglyphics...

The first step is to ensure that all variables with names starting s_ are removed from the environment. There's no special significance to s_ - it's just what I chose. The output of set s_ will be of the form s_whatever=something if an s_... variable exists. If none exist, the 2>nul suppresses the error message, but the > needs to be escaped by a caret (^) to tell cmd that the redirection is part of the command to be executed, not the for command. If s_whatever=something then the for /f will parse that line using = as a delimiter, hence assigning s_whatever to the nominated metavariable, %%i.

The next step is to find all of the .RDP filenames starting at the source directory. dir /s/b/a-d produces bare lines (no headers or footers) of the full filenames, suppressing any directorynames that happen to match the specified mask.

The entire filename is assigned to %%a because delims="" that is, there are no delimiters. S_ is used as a general-purpose variable and is assigned the drive and path parts of the filename in %%a. The last character of s_ is then removed (it will be a \) and the for /f %%b interprets the resultant string as though it was a filename. The variables s_#site and s_@site_machine are then set (to Y, but they could have been set to anything)

Note the use of !s_:~0,-1! which specifies to take character 0..last-1 of the run-time value of s_ - the ! specifies run-time value when SETLOCAL ENABLEDELAYEDEXPANSION is active.

The remainder of the main routine simply calls SHOWMENU twice with various parameters and assigns the value returned in s_ to the appropriate variable.

SHOWMENU sets the number of items (s_items) to 1 more than the count of items available, clears the screen and shows the menu title from the first subroutine parameter (%1) - but with the quotes suppressed (%~1) - which allows the parameter to contain spaces.

The following FOR/F tokenises the SET list for s_# (the SITE names) or s_@ (the SITE+MACHINE names). Using delimiters of _ and = as well as the # or @ means that for a line like s_#NSW=Y will assign NSW to %%i and a line like s_@NSW_Server01=Y assigns NSW to %%i and Server01 to %%j

The appropriate part is selected and passed to the SHOWLINE routine.

s_ is then used for user input. Forcing it to be cleared means that if the user presses just ENTER then it will remain unset - otherwise it would retain its original value.

I've arbitrarily assigned an input of Q to quit, and if there is no user input, then that quits, too. Otherwise, if the variable s_choicemade is set, then s_ is set to that value and reaching EOF returns from the subroutine. If an invalid choice is made, then s_invalidchoice will NOT be set, so the menu is re-displayed.

The SHOWLINE procedure sets s_ to spacethelinenumber.space and then the paraeeter is displayed (%1) preceded by the last 4 characters of that string. This means that if the item number exceeds 9 then the leading space wil be lopped off and the dots will be aligned. The item number is then incremented ready for the next choice.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Thank you @Magoo this was perfect. All i had to do was add `start mstsc %sourcedir%\%s_site%\%s_machine%.rdp /admin` above the `:showmenu` label and it worked exactly as i wanted. I'm still trying to get my head around how it all works but thank you for putting the time in to explain it for me. I noticed you put quit option in. I tried copying it to add a restart/back option with `IF /i "%_%"=="b" GOTO :start` (also added `:start` and `SET s_=` at top)but it just stays in the 'Machine' menu. Any ideas on how to add this instead of having to close then open again? – Durry42 Nov 19 '13 at 11:27