Running batch file from USB drive when drive letter changes - batch-file

So, I have made a batch script and it executes multiple portable programs (e.g., prog1.exe, prog2.exe, etc). The problem is whenever I connect the USB drive to another computer, the drive letters change, giving me errors when running my .bat file. Please help me find a solution. Thank you.

%~d0 gives you the current drive letter (including the colon). If the batch file's contained on the USB drive, you can use that.
So, for instance, instead of
E:\PortablePrograms\ProgramName.exe
you would write
%~d0\PortablePrograms\ProgramName.exe
... or you could do something like this
::change directory to the script's directory's drive
pushd %~d0
::navigate from the drive to the relevant path(s)
cd PortablePrograms
::execute any programs
ProgramName.exe
SecondProgramName.exe
::just because I like to pair my pushes with pops; not required
popd

This is how I get the last removable drive in a listing.
#echo off
:: Drivetypes
:: 0=Unknown
:: 1=No Root Directory
:: 2=Removable(USB,Firewire)
:: 3=Local Disk (Internal Hard Drive)
:: 4=Network Drive(\\Server\share\)
:: 5=Compact Disk (CD DVD)
:: 6=Ram Disk
for /f "tokens=2 delims==" %%d in ('wmic logicaldisk where "drivetype=2"
get name /format:value') do set driveletter= %%d
echo %driveletter%
pause

you can use command line argument %1, %2 as input path, and modify your bat file accordingly.

Related

Use a particular drive if path exists in a batch script

I have a batch file that sometimes people run and since batch files don't allow UNC mapping, they need specific drive mappings.
The problem is that some people who run this file will have the server mapped to different letters, specifically M or P.
So what I want to do is make a variable to score the drive so I can concatenate it into other path commands where possible because sometimes they will have:
M:\Path\to\stuff\on\server
or
P:\Path\to\stuff\on\server
So what I want to do is say if M:\Path\to\stuff\on\server" exists then use drive M, if "P:\Path\to\stuff\on\server" exists then use drive P.
Is there a way to do this in batch script?
Seeing as you specifically only have M: and P: in this example:
#for %%i in (m: p:) do #if exist %%i cd /d %%i
echo %cd%
It can be extended to more drives. Additionally please note that if the user has both M:\ and P:\ drives, it will cd to both and end up in the last one in the list. Therefore using a known directory is a better solution on the mapping.
#for %%i in (m: p:) do #if exist "%%i\Path\to\stuff\on\server" cd /d "%%I\Path\to\stuff\on\server"
echo %cd%
if you want to set it as a variable to use it anywhere else in the script, then simply assign the drive letter to a variable like so:
#for %%i in (m: p:) do #if exist %%i set "mydrive=%%i\"
echo %mydrive%
Alternatively, without needing to use variables, you can use the already assigned metavariable %%i to use the drive letter as you please:
#for %%i in (m: p:) do #if exist %%i (
echo my drive letter is %%i
dir %%i
cd /d %%i
)
One approach you could utilise is to create a temporary mapping using pushD.
pushd \\Server\Share\path
When you are done with that temporary mapping just use popd to destroy it.
Where \Server\Share\path is the network resource to which you want to map a drive letter.
As soon as you use it, the PushD command will instantly map a drive letter to the network resource and then change to that drive right in the Command Prompt window.
Keep in mind that the PushD command allocates drive letters from Z: on down and will use the first unused drive letter that it finds.

Batch: Preserve (creation-)date on copying files to another (flatten) folder structure, incl. renaming files to avoid doublettes

this is my first question, so I apologize beforehand if I write not as you are used to...
fact:
I've a deep folder structure with tons of files (images,videos and so on) so I want to copy that files to a flat structure for a better overview.
I want to keep (at least) the original date attributes: creation-date and last-modified date.
Problem 1) there are files with same name 00001.jpg in different folders which I want to have in same folder, so I want to add creation date/time to filename on copy process.
00001.jpg becomes 2015-11-17_11-23-35_00001.jpg
So far so good. Or not good...
Copy and XCopy doesn't give me an option to do that, without loosing at least the creation date information (I didn`t find a solution with both).
Now I try to copy the files (file by file) with robocopy to new folder and use ren on the copied file to "pre-set" the date/time information before the filename.
Here is a simple test.bat example:
setlocal enableextensions enabledelayedexpansion
robocopy . ./zzz original.txt /copy:DATSO
pause
rem :: formatted creation date of original file will be here, in real life
set "myDate=2015-11-17-_11-23-35"
rem rename "./zzz/original.txt" "!myDate!_renamed.txt" ::doesnt work: why? relative path??
rem :: this will do what I want - original creation date is kept on copy file
FOR %%A IN (zzz/original.txt) DO REN "%%~fA" "!myDate!_%%~nxA"
[possibly] Problem2) Is there a better way to do this, or could I run into thread problems (asynchronous execution). Could it be, that I try to rename a file before the robocopy has finished the copy process (e.g. for large files)?
Sorry I'm a totally batch newbie (also as poster in SO ;).
ThanX in advance for each tip and also for critics on my solution approach. Maybe I have the horse-blinkers on my head and dont see the easy solution?!
[edit: formatting of post]
[edit: content of post -> date/time in front of filename for better sorting]
It is possible to use command DIR to get recursive listed all files in the specified folder and its subfolders with creation date/time.
The format of the date/time depends on Windows Region and Language settings.
Example output for F:\Temp\Test on my machine with English Windows 7 and region is configured to Germany on running the command line dir F:\Temp\Test\* /A-D /S /TC:
Volume in drive F is TEMP
Volume Serial Number is 1911-26A4
Directory of F:\Temp\Test
25.09.2017 17:26 465.950 SimpleFile.ccl
1 File(s) 465.950 bytes
Directory of F:\Temp\Test\Test Folder
25.09.2017 17:26 360.546 Test File.tmp
1 File(s) 360.546 bytes
Total Files Listed:
2 File(s) 826.496 bytes
0 Dir(s) 58.279.460.864 bytes free
This output is filtered with findstr /R /C:"^ Directory of" /C:"^[0123][0123456789]" to get only lines starting with  Directory of (note the space at begin) or with a number in range 00 to 39.
Directory of F:\Temp\Test
25.09.2017 17:26 465.950 SimpleFile.ccl
Directory of F:\Temp\Test\Test Folder
25.09.2017 17:26 360.546 Test File.tmp
And this filtered output is processed by FOR loop and the commands executed by FOR.
#echo off
for /F "tokens=1-2*" %%A in ('dir "F:\Temp\Test\*" /A-D /S /TC ^| %SystemRoot%\System32\findstr.exe /R /C:"^ Directory of" /C:"^[0123][0123456789]" 2^>nul') do (
if "%%A %%B" == "Directory of" (
set "FilePath=%%C"
) else (
set "CreationDate=%%A"
set "CreationTime=%%B"
for /F "tokens=1*" %%I in ("%%C") do set "FileName=%%J"
call :RenameFile
)
)
goto :EOF
:RenameFile
set "NewName=%CreationDate:~-4%-%CreationDate:~3,2%-%CreationDate:~0,2%_%CreationTime:~0,2%-%CreationTime:~3,2%_%FileName%"
ren "%FilePath%\%FileName%" "%NewName%"
goto :EOF
It would be advisable to put command echo before command ren in last but one line to first verify the expected new file names.
ren "F:\Temp\Test\SimpleFile.ccl" "2017-09-25_17-26_SimpleFile.ccl"
ren "F:\Temp\Test\Test Folder\Test File.tmp" "2017-09-25_17-26_Test File.tmp"
Note: The batch file must be in a folder not processed by this batch file as otherwise the batch file itself would be renamed while running which breaks the processing of the batch file.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
dir /?
echo /?
for /?
goto /?
if /?
ren /?
set /?
By the way: WinRAR can add files into a RAR archive with creation and last access time in addition to last modification time and extract the files to a different directory with restoring also creation and last access time using SetFileTime function of Windows kernel.
currently I use Locale independent date. I use tokens from that for currrent date/time.
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set datetime=%%I
rem :: format it to YYYY-MM-DD_hh-mm-ss
set myDateTime=%datetime:~0,4%-%datetime:~4,2%-%datetime:~6,2%_%datetime:~8,2%-%datetime:~10,2%-%datetime:~12,2%
Thats not the problem.
To clarify:
The listing is also not the problem.
I loop throw all related files without a prob (except batch files and output dir and its sub tree ;).
My problem is:
I call robocopy for each file, then I rename the file to save the original creation date. My fear is that it makes problems (Multi-Threading?) for large files and for the number of calls (many thousend times)
Is batch execution really serialized? Is the process waiting for robocopy, that it has finished, before I try to rename file. Could I run into dead-locks for vry large files? I'll test it with some fake gigabyte-files.
Your suggestion, to use winrar sounds interesting.
If I could add all that files to a big archive (with structure) and at the end extract it to target dir... I'll try it ;)
If it doesn't work I will program it in java!
There I know what to do, thats my playground :D
I thought it would be easy to write a simple batch file, to do this for me, but it seems it's not as easy as I thought!
ThanX anyway

batch copy folder located by guid

In a batch file, can I copy a folder located by a constant path like \\?\Volume{GUID}?
When copying (copy, xcopy or robocopy) a directory and its content from a local removable drive (a usb external drive for instance) to another location on the same drive, I'd like to use unique and constant absolute paths like \\?\Volume{GUID} to avoid using drive letters that can change over time.
To operate the copy, the batch file is meant to be placed on the removable device, but in case the file is moved or placed somewhere else I'd rather be sure it's operating on the good drive.
So far I've tried:
COPY can handle \\?\Volume{GUID} paths to copy a file but cannot copy
folders
XCOPY returns an "invalid drive" error
ROBOCOPY gives a "network path not found, wait 30 sec..."
for each command above : syntax variations with \\?\UNC\Volume{guid} and with the trailing "\"
Am I doing something wrong or is this just not the way to do that?
Is there another way to use invariant locations?
Ideally it should involve the least tweaking possible. By tweaking I mean: labeling the drive or giving it a fixed letter, etc.
Have a look at pushd /? and popd /?
pushd \\?\UNC\Volume{guid}
will short time map the UNC path as a network drive and change the directory to it according to the next free drive of your computer from the end of the alphabet.
For example, you got Z:\ and Y:\ already it will map the path to X:\ and change the current directory to X:\.
From that on you can go for copy filefromServer.foo C:\localfile.bar
The other commands such as XCopy can use the mapped drive as well.
To unmap the drive use popd.
None of the copy function can work with unc path.
Thus the only way is a workaround that consists in retrieving the drive letter through wmic command.
Here's the code :
for /F "usebackq tokens=1,2 delims==" %%G in (`
wmic volume where "DeviceID='%_volID:\=\\%'" get DriveLetter /value
`) do set _%%G=%%H
with _volID being the variable containing the unc path of the volume in question

Open Batch Questions in a separate dialogue box.

I'm trying to make a Back Up.bat file using the RoboCopy command and am having some issues.
What I need is to back up a folder on to an external hard drive, and back up the same folder on to my laptop. My only issue is that the drive letter for my Hard Drive changes sometimes, I would just go to disk management and have a permanent drive letter, but I plan on having the folder backed up to multiple devices and don't want to have to repeat this again and again.
What I've tried so far is:
#echo off
robocopy "C:\Users\Zac\Desktop\Downloading" "%~d0\Backup\File Backups" /E /XF
robocopy "%~d0\Backup\File Backups" "C:\Users\Zac\Desktop\Downloading" /E /XF
I've also tried swapping the "%~d0" for a variety of drive letters, but got no where.
The easy way out is to make the drive letter permenent as shown in the Link.
you can look up the drive letter if you have the volume name:
set "drive=undefined"
for /f "tokens=2 delims=," %%i in ('wmic logicaldisk where (VolumeName ^= "ExternalDrive"^) get caption^,status /format:csv') do set drive=%%i
echo %drive%
where "ExternalDrive" is the volume name of your disk.
(Note: the property status is not used, it's just one of several ways to get rid of the ugly wmic line ending with the desired token caption)

WMIC Batch File

I am trying to use a .bat to get system info with WMIC. I want to create a folder in C:\ with the name of the computer, then have a few .txt files made within the folder with the info on I am seeking. This is what I have so far:
start cmd
cd C:\
md C:\%computername%_Software_Baseline
wmic
/output:C:\%computername%_Software_Baseline\Installed_Software.txt product get name,version
This is where my first roadblock is. I get the message that the file name is invalid. The next few are the other .txt files I want to create in that folder as well (Once I can do the first I should be able to apply it to these as well).
/output:C:\%computername%_Software_Baseline\Computer_System_Information.txt computersystem get domain,manufacturer,model,name,totalphysicalmemory
/output:C:\%computername%_Software_Baseline\Disk_Drive_Information.txt diskdrive get model,size,manufacturer
/output:C:\%computername%_Software_Baseline\CPU_Information.txt cpu get architecture,currentclockspeed,description,extclock,l2chachesize,manufacturer,name
/output:C:\%computername%_Software_Baseline\BIOS_Information.txt BIOS get serial number,name,smbiosbiosversion,manufacturer
/output:C:\%computername%_Software_Baseline\OS_Information.txt OS get name,cdsversion,manufacturer,freephysicalmemory,buildnumber
I also want this to save everything to a folder on my network as well, but that can wait until I get the script going.
I can't understand why not to perform the task within current cmd instance omitting start cmd:
#ECHO OFF
SETLOCAL enableextensions
md "C:\%computername%_Software_Baseline"
wmic /output:"C:\%computername%_Software_Baseline\Installed_Software.txt" product get name,version
or using pushd - popd command pair:
#ECHO OFF
SETLOCAL enableextensions
md "C:\%computername%_Software_Baseline" 2>NUL
pushd "C:\%computername%_Software_Baseline"
wmic /output:"Installed_Software.txt" product get name,version
rem further wmic commands here
popd
PUSHD: Change the current directory/folder and store the previous folder/path for use by the POPD command.
POPD: Change directory back to the path/folder most recently stored by the PUSHD command.
When a UNC path is specified, PUSHD will create a temporary drive
map and will then use that new drive. The temporary drive letters are
allocated in reverse alphabetical order, so if Z: is free it will be
used first.
POPD will also remove any temporary drive maps created by PUSHD.

Resources