# Okay another FOR SUBST Question



## scrfix (May 3, 2009)

This is just for practice and nothing else however I am a little stumped. I am practicing my FOR statement skills and I must say they are much much better than they were before. Not hard to beat since they were non existent before but I got pretty far with them this time before running into a stump.

*Ultimate Goal*
To list and store every drive letter used in the computer for CD-Roms, USB attached drives, network drives, virtual drives and physical drives (am I missing anything else that can have a drive letter?)

Not looking for one big glob of code that does this. The ultimate goal is to do this myself for practice however constructive criticsm, pointing me in the right direction and code examples for a specific troubled area are welcome.  I am starting with SUBST for virtual drives and will work on the rest as I go.

*The Command*
SUBST

*The preparation*
SUBST G: C:\Windows
SUBST H: C:\Windows\System32

*The FOR statment:*

```
@echo off
SET _var=
SET _var2=
FOR /F "tokens=1 delims=:" %%B in ('SUBST') DO (
SET _var=%%B
SET _var2=%%A
)
echo _var=%_var%
echo _var2=%_var2%
pause
```
*The Breakdown*
Set _var= (clear the _var variable)
Set _var2= (clear the _var2 variable)
FOR /F "tokens=1 delims=:" %%B in ('SUBST') DO
*FOR statement breakdown*
1. Run the command SUBST. Display the first token of each line output. In this case, this would be G:, H:
2. Set the deliminator as : so the output would be G on the first line and H on the next line.
Now correct me if I am wrong, shouldn't that constitute 2 variables being created in the FOR statement now? If there were 3 virtual drives then 3 variables, etc etc.
3. %%B (Temporarily store the result in the variable B, incrementally increase or decrease based upon lines found (ie. C, D, E or A)
)
4. DO (Do the items in the parenthesis )
SET _var=%%B (Equal _var to the value of variable B)
This ends up being H
SET _var2=%%A (Equal _var2 to the value of A)
Since the above is H, it only makes sense since I know that I am looking for the variable on the top line, to count down from B to A.
echo _var=%_var% (Display the value of variable _var to the screen)
echo _var2=%_var2% (Display the value of variable _var2 to the screen)
pause (Pause the batch file until someone pushes any key ont he keyboard except for Shift, CTRL, Windows Logo, Caps Lock, Right Click, Print Screen, Scroll Lock, Pause/Break, Num Lock or ALT)
(The statement push any key doesn't really mean ANY key. Thanks for the clarifiying statement Microsoft.)

The output that I am getting is:
_var=H
_var2=%A

I have even tried turning A to C and that didn't work either.
What am I doing wrong here?

I am attempting to retrieve the output of
_var=G
_var2=H

My next question after this, which I have no idea where to begin at, is since I know the amount of drives I can set the number of variables to look at. What happens if someone has X number of virtual drives. The way I wrote this, it will only do up to 2. Instead of writing SET _var1= SET _var2= Set _var3= ... Set _var26= how would I write it so that if I detect 7 virtual drive letters then it saves 7 variables for output. If there are 13 virtual drive letters, then it will save 13 variables, etc etc.

Thanks for any insight.


----------



## Squashman (Apr 4, 2003)

The For Loop parses line by line. So the first line of output equals G. You assign it to _var but then it gets over written when it parses the second line of output which makes _var equal to H.

You can't assign %%A to anything because it is non existent. You only have %%B because your tokens are equal to 1. And even if you did have more tokens defined the next one would be %%C because it goes in alphabetical order to assign the next token.


----------



## scrfix (May 3, 2009)

Thanks for the reply. That makes sense.

I am under the impression tokens= was for what to read not how many variables to output.

Such as parsing the following:
G:\: => C:\Windows
H:\: => C:\Windows\System32

(without the use of delims=
*Line 1*
Token 1 = G:\:
Token 2 = =>
Token 3 = C:\Windows

*Line 2*
Token 1 = H:\:
Token 2 = =>
Token 3 = C:\Windows\System32

Since I am using delims=: the tokens now change to:

*Line 1*
Token 1 = G
Token 2 = \

*Line 2*
Token 1 = H
Token 2 = \

I tried The following combinations thinking that the tokens was the original problem:


```
@echo off
SET _var=
SET _var2=
FOR /F "tokens=2 delims=:" %%B in ('SUBST') DO (
SET _var=%%B
SET _var2=%%C
)
echo _var=%_var%
echo _var2=%_var2%
pause
```
It outputs 
_var=\
_var2=%C

I have also attempted this combination thinking about the tokens


```
@echo off
SET _var=
SET _var2=
FOR /F "tokens=1* delims=:" %%B in ('SUBST') DO (
SET _var=%%B
SET _var2=%%C
)
echo _var=%_var%
echo _var2=%_var2%
pause
```
This is from a standard prompt and not an admin prompt

It outputs
_var=H
Access is denied.

And Administrative Prompt in Vista does absolutely nothing which I believe has to do with the fact that the virtual drives were created wtih the user token and the adminstrator cannot see them at all with his token. There is a reg hack for that so that the adminsitrator can share token access with the user. I am not currently using that reg hack so SUBST in an administrative prompt does absolutely nothing.

I have used @echo on with the last code and I get the following:

C:\Users\TEST\Desktop>sub2.bat
C:\Users\TEST\Desktop>SET _var=
C:\Users\TEST\Desktop>SET _var2=
C:\Users\TEST\Desktop>FOR /F "tokens=1* delims=:"
%B in ('SUBST') DO (
SET _var=%B
SET _var2=%C
)
C:\Users\TEST\Desktop>(
SET _var=G
SET _var2=\: => C:\Windows
)
C:\Users\TEST\Desktop>(
SET _var=H
SET _var2=\: => C:\Windows\System32
)
C:\Users\TEST\Desktop>echo _var=H
_var=H
C:\Users\TEST\Desktop>echo _var2=\: = 1>C:\Window
s\System32
Access is denied.
C:\Users\TEST\Desktop>pause
Press any key to continue . . .

I see where it is setting G to _var and where it is overwriting it.

How do I extract that value before it is overwritten and apply it to a variable that won't get overwritten?

How do I then do the same for the next value down the line so if there are 13 virtual drives it will extract all letters?

I have to head to work. I will not be back for another 12 hours at minimal however I do get the replies to my phone but I won't be able to test anything until I get back home.


----------



## Squashman (Apr 4, 2003)

Why don't you just write them out to a file and then use another for loop to parse the output file.


----------



## TheOutcaste (Aug 8, 2007)

scrfix said:


> ...Such as parsing the following:
> G:\: => C:\Windows
> H:\: => C:\Windows\System32
> 
> ...


You've got the idea of how tokens are assigned correct. I've added the ones in Red and fixed the smiley face.

The *Tokens=* parameter in the For statement determines which token (and how many) are assigned to the loop variable(s)
Consider this with different values for X:
*For /F "tokens=X" %%A In* ...
Tokens=1 means assign the 1st token to the loop variable A
Tokens=2 means assign the 2nd token to the loop variable A
Tokens=3 means assign the 3rd token to the loop variable A

Now consider this with different values for X and Y:
*For /F "tokens=X,Y" %%A In* ...
Tokens=1,2 means assign the 1st token to the loop variable A, the 2nd token to loop variable B
Tokens=2,3 means assign the 2nd token to the loop variable A, the 3rd token to loop variable B
Tokens=3,1 means assign the 3rd token to the loop variable A, the 1st token to loop variable B

Using a Range:
*For /F "tokens=X-Y" %%A In* ...
Tokens=1-2 Assigns two tokens, 1st to A, 2nd to B
Tokens=3-6 Assigns four tokens, 3rd to A, 4th to B, 5th to C, 6th to D

In all cases, any tokens not specified, or included in the range are ignored. If the token doesn't exist (Tokens=2,3 but only two tokens, so number 3 doesn't exist) it won't be assigned and the loop variable (B in this case) will be undefined.


scrfix said:


> This is from a standard prompt and not an admin prompt
> 
> It outputs
> _var=H
> Access is denied.


The Access is denied message isn't because you aren't running in an admin prompt.
*subst* outputs the following:
G:\: =*>* C:\Windows
H:\: =*>* C:\Windows\System32
so your echo statement is:
echo _var2=\: =*>*C:\Windows\System32
This translates to "echo this: *_var2=\: =* and redirect it to the file *C:\Windows\System32*"
You'll notice the line was changed from "=*>* C" to "= *1>*C"
The number 1 indicates it's redirecting STDOUT.
The error is because *C:\Windows\System32* is not a file but a folder.


scrfix said:


> I see where it is setting G to _var and where it is overwriting it.
> 
> How do I extract that value before it is overwritten and applie it to a variable that won't get overwritten?
> 
> How do I then do the same for the next value down the line so if there are 13 virtual drives it will extract all letters?


Since the Echo is outside the loop, it only shows the last value for the variables. If you need to save them, you need to use DelayedExpansion and a count variable to give a different name for each variable:

```
@Echo Off
SetLocal EnableDelayedExpansion
:: Clear 26 variables
For /L %%I In (1,1,26) Do Set _Var%%I=
Set _Count=0
For /F "Tokens=1 Delims=:" %%B In ('SUBST') Do (
Set /A _Count+=1
Set _Var!_Count!=%%B
)
:: _Count is now equal to the number found
:: Display the list with another For loop
For /L %%I In (1,1,%_Count%) Do Echo _Var%%I=!_Var%%I!
```
You can use WMIC to get the drive letters (see this post), but you have to be running the Professional or higher version of Windows.

You can also read the drive letters from the Registry for all drives except those that are created by *subst*.
They are located here:
HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices

Note: As Squashman just reminded me, MountedDevices will list all drive letters, even for devices that are not connected. So if you want connected drives, you'd have to test to see if they are present if reading them from the registry


----------



## scrfix (May 3, 2009)

Thanks for that.

I knew about WMIC. I did not know that you needed professional or higher for it to work. WMIC is where I was heading next after I did this. I knew that I could utilize it to detect CD-Rom devices, Network Drives and Physical and Removable Drives.

Testing the drives is also an option depending on the test. I cannot just do an IF EXISTS because if there is no CD in the CD-ROM it doesn't detect it as a drive.

How would you test for the drives if not a FOR loop looping through all 26 letters with an IF Exists?

Let's give an example here because I am not curious of something.

How would I detect what drive letters are being used on Windows XP Home Edition?

I know that I can test SUBST for virtual drives.
I know that I can do a FOR statement and loop through all 26 letters with an IF Exists statement for the physical and removable devices such as flash and external drives.

How do I test for CD-Roms and Media Card Readers that have no media in them? If Windows XP Home does not have WMIC, how does one accomplish this? Possibly Disk Management then. Disk Management would provide CD-Rom Drive Letters I believe. I have not tested this however.


----------



## scrfix (May 3, 2009)

Damn,

I just read your FOR Loop. I have a lot more practice and studying to do. 
I wasn't even in the same ball park less the right direction with where I was going to be able to do what I was attempting to do.

Thanks for the example,

Still am worndering about detecting drive letters on XP Home. I don't have any XP Home systems to test here at the house. I do have some at the shop though.

Happy New Year everyone.


----------



## TheOutcaste (Aug 8, 2007)

I'm still learning about *For* myself. Didn't realize until today you could do *tokens=3,1* to change what piece gets assigned to what loop variable. Not something you'd use a lot, but could be useful in some cases.

Don't have an Xp Home system handy at the moment, but I think systeminfo may provide the info on drives.

Happy New Years - 95 minutes and counting...


----------



## scrfix (May 3, 2009)

You are still learning about FOR statements?
Huh? You are the GOD of batch! Everything you write is completely gold and just works. Short of the statement that nobody knows everything but I am as close as you can get, I wouldn't believe that you are still learning about FOR statements.

You are two hours behind me. It is 1:28am where I am at.

I will look into systeminfo when I get to the office on Saturday.


----------



## TheOutcaste (Aug 8, 2007)

That would be three hours then, was 10:25 PM here.

Still learning new tricks would get boring if i couldn't find something new.

I can fire up an XP Home VM now, so I'll find out in a few minutes.


----------



## TheOutcaste (Aug 8, 2007)

XP Home doesn't have systeminfo either. You might be able to run it from another system, systeminfo does have the /S switch, but would probably take some configuration on the target box to allow it.

Looks like you can probably use msinfo though. It does have some command line options, and can silently save a text report and/or info file. The text report can probably be parsed by a For loop.
Looks like you can specify categories for the report, so you may be able to just output the disk info.
type "C:\Program Files\Common Files\Microsoft Shared\MSInfo\msinfo32.exe" /? in a prompt or the run box to see the options.

Should be the same on XP Pro. Have to check Vista/7 next, see if they are also missing systeminfo


----------



## scrfix (May 3, 2009)

msinfo32.exe is available on Vista however /? just brings up the GUI help menu.

How about querying the device manager? Is there any way to do that in the command line?


----------



## scrfix (May 3, 2009)

I found a couple of VB Scripts to determine the next available drive letter however I don't know if they will work for Windows XP Home Edition.

http://blogs.technet.com/heyscripti...ext-available-drive-letter-on-a-computer.aspx

http://windowsitpro.com/article/art...le-drive-letter-when-z-is-already-mapped.html

http://www.neowin.net/forum/index.php?showtopic=606906

I am sure these can be turned to Batch

(And look at the last one. I am not the first one to ever name their batch file subst.bat)

he last one says it is a batch but it is clearly a vbs??


----------



## TheOutcaste (Aug 8, 2007)

While XP Home doesn't have *systeminfo.exe*, Vista Home does. I suspect Win 7 Home does as well. Not sure about Starter and Basic, but probably included as well, at least in Basic.

*msinfo32* doesn't display help in Vista or Win 7, but the */report* feature works, at least on Win 7. It generates the complete report though, you can't select categories as you can in XP, and it displays a GUI progress window as it creates the report. Haven't tested in Vista Home yet.
It's a TAB delimited report.
MSINFO32 Command Line options

So I would check version, use WMIC if available, then systeminfo, then msinfo32.
*msinfo32* has the advantage on XP of being able to limit the output to a specific category. *systeminfo* always generates the complete report, but can be output as a table or in CSV format. So both may be useful depending on what info you need.

The first script works on XP Home. Note that the last quote is a "curly" quote, so will have to be changed to a standard double quote for the script to compile.

That last one is vbs, sounds like he tried both batch and vbs but was naming them subst.bat and subst.vbs.

Here's the list of categories you can specify with msinfo32 on XP. *Components* is a category, not just a heading in the list. The SystemSummary is always included in the report, as are the category headings, upto the last category included in the report.
Also noticed a *subst* drive will have the same *Volume Serial Number* as the source drive, so two drives with the same *Volume Serial Number* means one of them is a *subst* drive.

```
SystemSummary
Resources
  ResourcesConflicts
  ResourcesDMa
  ResourcesForcedHardware
  ResourcesIO
  ResourcesIRQs
  ResourcesMemory

Components
  ComponentsMultimedia
    ComponentsMultimediaAudio
    ComponentsMultimediaVideo
  ComponentsMultimediaCDROM
  ComponentsMultimediaSound
  ComponentsDisplay
  ComponentsInfrared
  ComponentsInput
    ComponentsKeyboard
    ComponentsPointDev
  ComponentsModem
  ComponentsNetwork
    ComponentsNetAdapter
    ComponentsNetworkProtocol
    ComponentsNetworkWinSock
  ComponentsPorts
    ComponentsSerialPorts
    ComponentsParallelPorts
  ComponentsStorage
    ComponentsStorageDrives
    ComponentsStorageDisks
    ComponentsStorageSCSI
    ComponentsStorageIDE
  ComponentsPrinting
  ComponentsProblemDevices
  ComponentsUSB

SWEnv
  SWEnvDrivers
  SWEnvSignedDrivers
  SWEnvEnvVars
  SWEnvPrint
  SWEnvNetConn
  SWEnvRunningTasks
  SWEnvLoadedModules
  SWEnvServices
  SWEnvProgramGroup
  SWEnvStartupPrograms
  SWEnvOLEReg
  SWEnvWindowsError

InternetSettings
  InternetExplorer
    IESummary
    IEFileVersions
    IEConnectivity
    IECache
      IECacheSummary
      IECacheObjectList
    IEContent
      IEContentSummary
      IEContentPersonalCertificates
      IEContentOtherPeopleCertificates
      IEContentPublishers
    IESecurity
```


----------



## Squashman (Apr 4, 2003)

How bout just using psinfo?


----------



## scrfix (May 3, 2009)

Thanks for the information on that. I will look into that as soon as I get a chance. Lately my weekends which I usually get to study this stuff are taken. I am currently running gigabit networking throughout my house.

Squashman,

What is psinfo? I attempted to use it in the command line for Vista and it came back unknown.

*Updated*
Nevermind. I looked up psinfo. That may work manual individual use. I like a lot of those sysinternal tools. They work great for indivudal use however if you ever want to automate them into anything they come up with that stupid pop-up that you have to click first before it allows you to utilize the tool which completely prevents automation of any kind which if you are putting it into a batch file is what you want unless you are manually running the batch file.


----------



## Squashman (Apr 4, 2003)

You should read this.
http://forum.sysinternals.com/forum_posts.asp?TID=8783&PN=1
http://blogs.technet.com/sysinternals/archive/2006/12/05/updates-pstools-and-sysinternalssuite.aspx
http://forum.sysinternals.com/forum_posts.asp?TID=9038


----------



## scrfix (May 3, 2009)

Thanks. That makes things a lot easier when using those tools. I will try that. You have a gift for being able to find ANYTHING on the Internet. One of my technicians is like that. I searched for two days for Vista drivers for an all-in-one sony desktop because sony did not put them on their website. He found them in 10 minutes.

He has some weird algorithm that he uses in Google that shouldn't work but it does. It includes using the & and + signs. I know what they mean in google and it shouldn't work but it does.


----------



## Squashman (Apr 4, 2003)

I didn't do anything weird when Google searching for that.


----------

