Jump to content

Batch Script Tips and Tricks for XPCDs


Recommended Posts

One problem in building our XPCDs is that we cannot know the CD-ROM's drive letter in advance. This is because we may have several hard drive partitions, optical drives, and other removable drives. Windows Setup Text Mode assigns it's own letters to these volumes. And from PC to PC the assigned letters will be different, based on a number factors: drive type; volume format; partition is active, primary, or extended; et. al.

To counter this you may have seen many command script examples at this web site and others which include a routine to identify the CDROM drive letter. Most of these techniques rely on checking for the existence of a known file on the CD-ROM at each possible drive letter (checking all letters C through Z inside of a For-In-Do loop). There are also other variations on these technique (many you will see in this thread).

But there are issues with such techniques:

• The code is less modular. I prefer modular code so when I move to my next project, I copy and past modules from previous scripts to new ones. When you check for a specific file, folder, or volume label, then you must make damned sure it is actually on your XPCD, and you must also make damned sure it is not on any other drive that may be attached at the time you install from your XPCD. What happens when you rebuild your PC, but you leave your other HDD partitions intact? The For-In-Do Loop Checks search all drives looking for its check file/folder/label. Such a check doesn't stop once it has found the first instance. So if you have the same check file/folder/label in more than one drive, you will not get the correct drive letter assigned to the %CDROM% variable.

• Even more critical is something that happens if you have more than one CD-ROM drive installed (which I do). A For-In-Do with a File/folder/volumename check searches all drives (C-Z), including a second CD drive that you may or may not have a CD in. It doesn't matter what these techniques are looking for, it is the very fact that they check every drive C-Z that causes the problem. Empty CD drives (and other drive types such as Iomega Rev) will cause errors when the Windows shell tries to check them for a file, or a label or whatever. Windows will put a dialog up on the screen and halt the installation until you respond:

"'Windows No Disk' 'There is no disk in the drive. [Cancel] [Try Again] [Continue]"

I personally find this problematic. In my opinion the behavior above just chopped the "Unattended " off of "Unattended Installation." I don't know about you, but I want code that allows me to stick in a XPCD and go work on something else while the PC installs itself.

But, there is a much simpler technique provided by the Windows XP Command Prompt script language, if one is executing a command script from the CD-ROM itself (as opposed to first copying the script to the hard drive and executing it from there). Assuming you are using Windows XP, or later, you can use Batch Parameter Expansion (search for "Using batch parameters" in the Windows XP Help and Support Center). When any command script executes, its first parameter, %0, equals the command script file name. However using parameter expansion, we can derive the CD-ROM drive letter from %0 by using: %~d0.

For a simple practical example, simply copy the code below and paste it into a command file and execute it:

@Echo OFF
SetLocal enableextensions
CLS
Echo.
Echo I am file (not yet expanded): %0
Echo My Expanded File Name: %~n0
Echo My Expanded Extension: %~x0
Echo My Expanded Name and Extension: %~nx0
Echo My Expanded Drive: %~d0
Echo The Expanded Root of My Drive: %~d0\
Echo Some Other Expanded Path on My Drive: %~d0\SomeOtherPath
Echo My Expanded Path: %~p0
Echo My Expanded Drive and Path: %~dp0
Echo.
Pause

EndLocal
GoTo :EOF

Like Yzöwl states below for Windows 2000, the Endlocal, and Goto:EOF at the end are not strictly required (but they are great programming structure). There is always one implicit EndLocal at the end of each command script in Windows XP. However, if you nest Setlocals, you should definitely use matching EndLocal statements.

While undocumented in the Windows XP Help and Support Center (surprise :realmad:), testing reveals that command extensions also NEED to be enabled in Windows XP for batch parameter expansion to work (but they are enabled by default in XP). There are two methods available to enable command extensions. One is to use:

SetLocal enableextensions

The other is to start your command script with the following command:

Cmd /e:on ScriptName.cmd

the code above to shows the first method.

This technique allows you programmatically account for differing CD/DVD-ROM drive letters from PC to PC. It only works because the command script resides on the CD-ROM drive. If you move the script above to another volume, you will get different values. To illustrate, copy the sample script above to different volumes and execute it from each--all the values above that use the d modifier will change. You cannot manipulate batch parameters in the same manner that you can manipulate environment variables. You cannot search and replace values or examine substrings. However, you can assign the parameter to an environment variable, and then manipulate the environment variable.

What makes the technique so powerful is that it doesn't require a check file, folder, or label. It doesn't care how many drives you have--it's not looking for any of them. When any script with

Set CDROM=%~d0

in it runs from the CD/DVD drive your XPCD is in, it will automatically and programmatically know the CD-ROM drive letter. It's just so much simpler to type, takes less time to execute, and is much less problematic. All the upside in the world, and no downside.

[Edit: 2005-09-22]

Since I've received questions about this original topic offline, I've decided to create and share a script people can plug into their XPCDs that solves all ambiguity as to how this technique should be employed. It is tested on Windows XP, and should work as well on Windows 2000. Download the .zip file, extract it, open the .cmd and read it. It should explain everything in sufficient detail. Post any questions to this thread.

Variables set in any script launched from CmdLines.txt do not live past the life of that script. MapCD must be called from the top of each script launched from CmdLines.txt, as %CDROM% will destroyed after each script called from CmdLines.txt ends.

[/Edit: 2005-09-22]

[Edit: 2005-09-23]

MakeMapCD.zipCurrent Version: v1.1.1

Changes from v1.1 are mostly organizational and documentation. The original version I posted (v1.1) will still work just fine, so long as MapCD is called from the top of any of your scripts (which was my recommendation all along).

[/Edit: 2005-09-23]

Hope you find this useful! B)

If you have a script tip or trick that applies to unattended XPCDs post it to this thread.

Keywords: CD CD-ROM DVD DVD-ROM drive drives letter letters find locate assign obtain acquire get set %CDROM% unattended installation XPCD windows xp 2000 batch command script tip tips trick tricks technique techniques

Edited by DarkShadows
Link to comment
Share on other sites


For win2k just start the batch with

  • @echo off
    setlocal enableextensions

you should end it with

  • endlocal
    goto :eof

correct but not strictly necessary

<Edit>I've added a couple of extras to this one, there are other combinations though

@echo off
setlocal enableextensions
cls
echo.
echo     I am file (not yet expanded):         %0
echo     My Expanded File Name:                %~n0
echo     My Expanded Extension:                %~x0
echo     My Expanded Name and Extension:       %~nx0
echo     My Expanded Drive:                    %~d0
echo     The Expanded Root of My Drive:        %~d0\
echo     Some Other Expanded Path on My Drive: %~d0\SomeOtherPath
echo     My Expanded Path:                     %~p0
echo     My Expanded Drive and Path:           %~dp0
echo     My Expanded full filename and path    %~f0
echo     My Expanded short filename path       %~dps0
echo.
pause
endlocal
goto :eof

</Edit>

<Edit2>

Although not related to XPCDs, this one gives you a nice little example using the above

@echo off&setlocal enableextensions
md "%~dp0test"
copy %0 "%~dp0test"
del %0

Put this one on your Desktop naming it test.cmd, double click it, and keep your eyes on it at the same time.

</Edit2>

Edited by Yzöwl
Link to comment
Share on other sites

Is there a reason why you have

SetLocal enableextensions

@Echo OFF

instead of

@Echo OFF

SetLocal enableextensions

It should make a difference, but your method will echo that first line.

Edited by Gee
Link to comment
Share on other sites

Is there a reason why you have

SetLocal enableextensions

@Echo OFF

instead of

@Echo OFF

SetLocal enableextensions

It should make a difference, but your method will echo that first line.

:w00t: Whoops! Thanks for pointing that out! I'll edit the first post accordingly
Superb!  @DarkShadows, your effort is really appreciable!  The guide is really great especially for persons like me who keep hunting for sources here and there.  Good job! :thumbup

Thank you. Glad it helps.
Nooooo! All my secrets! Published for all to see!

:} Sorry Nois3! But for a small ransom, I won't reveal your secret identity, nor the location of your hideout! :sneaky:
Link to comment
Share on other sites

Please do not let the size of this bother you almost 1/3 of the lines are for asking if you want to keep or delete the the file.

This is not a batch file but a VBS script it will list all instances of a file named win51ip regardless of extention.

Save This As Seekwin51ip.vbs

Red Is The Question To Either keep Or Delete The File. This Can Be Removed From The Script

Green Is The File It Searches For

Dim Act : Set Act = CreateObject("Wscript.shell")

Sd = Act.ExpandEnvironmentStrings("%systemdrive%")

UN = Act.ExpandEnvironmentStrings("%UserName%")

Dim StrComputer, Tfile

TFile = (Sd & "\TempList.txt")

strComputer = "."

  Function Search_File

  Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

  Set colFiles = objWMIService.ExecQuery("Select * from CIM_DataFile Where FileName =  'win51ip'")

  If colFiles.Count = 0 Then

  Act.Popup "No File Exists With That Name", 3,"Gsm No File", 0 + 32 '''' If The File Is Not There

  Exit Function

  End If

  Set objFSO = CreateObject("Scripting.FileSystemObject")

  Set objTextFile = objFSO.CreateTextFile(Tfile) '''' The Text File That It Makes

  For Each objFile in colFiles

  Kbname = Ucase(objFile.FileName & "." & objFile.Extension) '''' Makes The Whole File Name In Upper Case

  KbPath = UCase(objFile.Drive & objFile.Path) '''' Makes The Whole Path To File In Upper Case

  TheFile = KbPath & Kbname '''' This Makes The Full Path And File Name And Extention

  Line1 ="=========================================" 

  objTextFile.Write( Line1 & "{File Name And Location}" & Line1 & vbCrlf & vbcrlf & Kbpath & Kbname & vbCrLf & Vbcrlf)

  Next

  objTextFile.Close

  Act.Popup "Completed The Search", 3, "Gsm Search File", 0 + 32

  Act.Run(Sd & "\TempList.txt"),1,True

  '''' Ask If You Want To keep Or Delete The File

  Question = Act.popup(_

  Un & VbCrlf & "Did You want To Keep The " & Tfile & VbCrlf & "Yes To Keep The File" &_

  VbCrlf & "No To Delete The File" & VbCrlf & "If Nothing Is Selected After 15 Seconds Then" &_

  VbCrlf & "It Will Delete The File", 15, "Gsm Keep Or Delete", 4 + 32)

  If Question = 6 Then

  Exit Function

  End If

  If Question = 7 Then

  ObjFSO.DeleteFile(Sd & "\TempList.txt")

  Exit Function

  End If 

  If Question = -1 Then

  ObjFSO.DeleteFile(Sd & "\TempList.txt")

  Exit Function

  End If 

  End Function

  Search_File

And This One Is Where You Type The Name Of The file You Would Like To Search For. Save As UserSeekFile.vbs

Purple Is The User Input That Get The Name, Plus A Part That deal With Quiting And Continuing On with The script.

Red Is The Question To Either keep Or Delete The File. This Can Be Removed From The Script

Dim Act : Set Act = CreateObject("Wscript.shell")

Sd = Act.ExpandEnvironmentStrings("%systemdrive%")

UN = Act.ExpandEnvironmentStrings("%UserName%")

Dim FName, StrComputer, Tfile

TFile = (Sd & "\TempList.txt")

strComputer = "."

  Function Search_File

  UserIn = Inputbox(Un & VbCrlf & "Type In The Name Of The File You would Like To Search For." & VbCrlf & "This Does Not Need Any Extention, Adding The Extention Will Cause A False Search Result","Gsm Name The File","")

  If UserIn <> "" Then

  Else

  Gsm1 = Act.popup (Un & VbCrlf & "This Needs A Name To Complete The Search" & VbCrlf & Un & " Did You Want To Quit Or Continue?" & VbCrlf & "Yes To Continue" & VbCrlf & "No To Exit" & VbCrlf & "After 30 Seconds This Will Exit", 30,"Gsm Continue Or Quit", 4 + 64)

  If Gsm1 = 6 Then

  Search_File

  Else

  If Gsm1 = 7 Then

  Wscript.quit

  Exit Function

  End If

  If Gsm1 = -1 Then

  Wscript.quit

  Exit Function

  End If

  End If

  End If

  FName = UserIn

  Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

  Set colFiles = objWMIService.ExecQuery("Select * from CIM_DataFile Where FileName = '" & FName & "'")

  If colFiles.Count = 0 Then

  Act.Popup "No File Exists With That Name", 3,"Gsm No File", 0 + 32 '''' If The File Is Not There

  Exit Function

  End If

  Set objFSO = CreateObject("Scripting.FileSystemObject")

  Set objTextFile = objFSO.CreateTextFile(Tfile) '''' The Text File That It Makes

  For Each objFile in colFiles

  Kbname = Ucase(objFile.FileName & "." & objFile.Extension) '''' Makes The Whole File Name In Upper Case

  KbPath = UCase(objFile.Drive & objFile.Path) '''' Makes The Whole Path To File In Upper Case

  TheFile = KbPath & Kbname '''' This Makes The Full Path And File Name And Extention

  Line1 ="=========================================" 

  objTextFile.Write( Line1 & "{File Name And Location}" & Line1 & vbCrlf & vbcrlf & Kbpath & Kbname & vbCrLf & Vbcrlf)

  Next

  objTextFile.Close

  Act.Popup "Completed The Search", 3, "Gsm Search File", 0 + 32

  Act.Run(Sd & "\TempList.txt"),1,True

  '''' Ask If You Want To keep Or Delete The File

  Question = Act.popup(_

  Un & VbCrlf & "Did You want To Keep The " & Tfile & VbCrlf & "Yes To Keep The File" &_

  VbCrlf & "No To Delete The File" & VbCrlf & "If Nothing Is Selected After 15 Seconds Then" &_

  VbCrlf & "It Will Delete The File", 15, "Gsm Keep Or Delete", 4 + 32)

  If Question = 6 Then

  Exit Function

  End If

  If Question = 7 Then

  ObjFSO.DeleteFile(Sd & "\TempList.txt")

  Exit Function

  End If 

  If Question = -1 Then

  ObjFSO.DeleteFile(Sd & "\TempList.txt")

  Exit Function

  End If  

  End Function

  Search_File

Link to comment
Share on other sites

GREAT WORK !!!! :thumbup:thumbup

--> That saves me the hassle of coding my brains out to derive the Windows XP source path from the registry during setup !!!!!

Thanks, so simple and so unthinkable !!!

(NB: Using this method is better in RunOnceEx, as this method guarantees that the batch file will always correctly set the source path of the Windows source!! regardless of whether the source is on the CD-ROM or on a folder on the hard drive !!!!)

(*** runs off to Notepad2 to edit RunOnceEx.cmd code...)...

Link to comment
Share on other sites

I am using this for my UNC based installations... Which is quite good way.

When I wanted to detect CDROM drive, I am using different method than most people here - my solution is based on cd name. E.g. find drive, where name is "Unattended installation" and set it as source (using WMI classes)

Link to comment
Share on other sites

I found this code on Microsoft this does not need a check file and will

list the Cd Drive

Just For Drive Letter

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colItems = objWMIService.ExecQuery("Select * from Win32_CDROMDrive")

For Each objItem in colItems

  CreateObject("Wscript.Shell").Popup  "Your Cd Is" & vbCrLf &  objItem.Drive & "\" , 4, "Cd = " & objItem.Drive , 0 + 32

Next

This One I Made Based On The Above Script It Checks To See If XP Is In The CDROM

Blue Is The Part Of The Script That Checks To See If A XP In The CDROM

Green Is The Cd Varible And File It Checks For

Dim strComputer : strComputer = "."

Dim Act : Set Act = CreateObject("Wscript.Shell")

Dim Fso : Set Fso = CreateObject("Scripting.FileSystemObject")

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colItems = objWMIService.ExecQuery("Select * from Win32_CDROMDrive")

For Each objItem in colItems

Dim Cd : Cd = objItem.Drive

Next

If Fso.FileExists(CD & "\i386\winnt32.exe") Then

Act.Popup "This Is The Correct Cd" & vbCrLf & CD & "\i386\winnt32.exe", 5, CD & " Confirm"

Else

If Not Fso.FileExists(CD & "\i386\winnt32.exe") Then

Act.Popup "This File Was Missing" & vbCrLf & CD & "\i386\winnt32.exe", 5, CD & " Missing"

End If

End If

Link to comment
Share on other sites

This one is for Windows XP

It will tell you your CD-Drive letter(s), without the needing any disk in it

@echo off
for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
 fsutil fsinfo drivetype %%a:|find "CD-ROM">nul 2>&1&&echo/%%a:
)
pause&goto :eof

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...