My users are use to map network drives.
I developed a tools, which use a network drive i:.
Problem : I may overlap a user-defined drive.
How can I open a dos batch file which will define a new network drive for its own usage but that will not change the network drives visible by the user?
you can use
pushd \\server\share
it will map a drive on the first available letter
the drive will be disconnect when running popd
Current directory may be obtained through the environement variabble %cd%.
You can use a for loop to find an available drive letter.
for %%d in (z y x w v u t s r q p o n m l k j i h g) do if not exist %%d:\* set drive=%%d
Then use %drive%: in place of I: throughout your bat file.
e.g. net use %drive%: \\server...
The drive letter system is nowadays quite outdated, you may want to substitue yourself in the path.
s/^i:\/\\SomeServer\SomeShare\
Cordially
Related
I try to use USBDLM to connect separately a USB sticks and a USB drive to appear always as drive T.
On every USB stich/drive I put a USBDLM.ini with:
[DriveLetters]
Letters=%drive%\usbdlm.ini
and for every drive its own configuration as:
[DriveLetters10]
; Aldistick
DeviceID1=USB 2.0 Flash Disk USB Device
Letter1=T
; many other options are documented in the Help files
[DriveLetters20]
VolumeSerial=16ED-33C5
Letter=T
But I find out that this is not working unless I put the same usbdlm.ini file for every stick/drive into the folder where USBDLM.exe is placed.
Do I something wrong?
Thanks.
On the drive you need an USBDLM.INI which contains a simple [DriveLetters] section with the desired letters:
[DriveLetters]
Letters=T
In the main USBDLM.INI you let is read the letter from the INI on the drive:
[DriveLetters]
Letters=%drive%\usbdlm.ini
Maybe it is more handy to let USBDLM extract the desired drive letter from the volume label, e.g. label it "Drive T" and write in the main USBDLM.INI:
[DriveLetters]
Letters=%LetterFromLabel%
http://www.uwe-sieber.de/usbdlm_help_e.html#by_label
Uwe Sieber
MSDN has a nice example of changing drive letters at:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa364014(v=vs.85).aspx
Only problem is that it doesn't work on my Windows 7 system.
Am invoking the EXE from a DOS window with admin privileges.
I start with a thumb drive on E:
I can use the MSDN example to remove E:
But when I then use the MSDN example to assign F: to the same thumb drive, the initial DefineDosDevice for F: succeeds, but the subsequent GetVolumeNameForVolumeMountPoint fails thus SetVolumeMountPoint fails.
I understand that the function of the initial DefineDosDevice is to create the drive letter so there's something for GetVolumeNameForVolumeMountPoint to connect to and thus return the volume name, but GetVolumeNameForVolumeMountPoint is behaving as if the intial DefineDosDevice has failed.
Whassup?
The problem was the second argument to ChangeLetter.exe when defining a new drive. You must include the partition number. Assume USB drive is set for E: and you want to move it to F:. You must do the following:
ChangeLetter -r E:
ChangeLetter F: \device\harddisk1\partition1
Harddisk counts from zero. Partition counts from one.
update SOLVED - the problem is not with my code. there is a design limitation (some might say "bug") in the command processor. the IF comparison operators do not work with values higher than 2147483648. now I just have to figure out how to strip off some of the least significant digits for the workaround. thanks to all for reading.
=======
hello out there in cyberland,
I manage a small company's network. I'm trying to set up an automated archival process using a batch file running on a server, and need a little help with the logic. I'm not a programmer and don't have the time to learn PowerShell or VBscript. I have read and re-read the MS command reference on IF, FOR, and CALL, and can not figure out what I'm doing wrong.
We have a Windows 2000 Server with two disk drives and a tape drive. One disk has a shared folder, call it Public; the other disk is not shared, call it Staging.
The Public drive will accept incoming backups from the client desktops. I need the process to move files from the Public drive to the Staging drive until the drive is too full to accept any more files, whereupon the tape backup starts. Upon completion of the tape run, the Staging drive will be emptied and the process will resume moving files from Public to Staging.
The goal is to automatically and perpetually archive the desktop backup files to tape, with no user intervention other than changing the tape.
You may ask, why involve two drives? Two reasons:
1) If the desktops back up directly to the Staging drive, at some point the client desktop backups will fail for lack of space on the target drive. I have no way to predict when this will occur; the only definable condition I can think of would be an arbitrary threshold of free disk space, but since the backup files to be archived will be different sizes, I could run into a situation where the target drive free space is above the threshold, but the next backup exceeds that space. Result: client desktop backup fails and server tape backup does not start.
2) If the Staging drive fills up and the tape backup fails for some reason (tape not changed or whatever), having the desktops back up to the Public drive buys me some time to fix the tape issue before the desktop backups begin to fail.
Here is the algorithm I'm trying to code:
1) Begin
2) Obtain free space on Staging drive
3) Obtain size of smallest file on Public drive (if no files present, exit)
4) Compare file size with free space on Staging drive
5) if file will fit, move it to Staging drive; else, exit and start Tape Backup
6) return to Begin
And here is my batch code which is not working. At this stage in testing, I have one file (8 GB) in the Public drive which will fit in the free space (32 GB) on the Staging drive. The set command confirms the variables are being set as expected; the process is failing at the statement [ if %BKFsize% LSS %DiskFree%" ]. Instead of the file being moved, the tape routine specified by 'else' is called instead:
#echo off
setlocal enableextensions enabledelayedexpansion
:Begin
REM obtain and display free space on Staging drive.
D:
for /f "tokens=3 delims= " %%A in ('dir ^| find "bytes free"') do (
set Z=%%A
set Z=!Z:,=!
)
set DiskFree=!Z!
echo.
echo D: has %DiskFree% bytes free
echo.
REM obtain sizes of files on Public drive to be moved.
E:
cd \backup.email
if not exist *.bkf exit
dir *.bkf /b /os > BKFlist.txt
for /f "tokens=*" %%G in (BKFlist.txt) do call :CheckBKF "%%G"
goto :eof
:CheckBKF
set BKFfile=%1
set BKFsize=%~z1
echo.
echo File %BKFfile% is %BKFsize% bytes
echo.
set
pause
REM move file(s) to Staging drive, space permitting; or,
REM if not enough space for smallest file, start tape backup.
if %BKFsize% LSS %DiskFree% (
echo Moving file %BKFfile% to drive D
echo.
move E:\backup.email\%BKFfile% D:\backup.email
) else (
C:\WINNT\AutoBackup\TapeBKF.cmd
exit
)
goto Begin
:End
I know this must be fairly simple but like I said, I'm not a programmer, and I bow to your superior skill. Any advice is much appreciated, and thank you.
In batch file, there is no real difference between strings and integers types, but that isn't your problem here.
The problem is that integers only works in the 32 bit signed range.
-2147483648 to 2147483647
But your filesize is greater and also your disk space.
To test this you could try to add a one.
Set /a myvar=BKFsize+1
Set /a myvar=DiskFree+1
I suppose you get an error.
You could solve it, if you try to use the string compare, currently you do a string compare but your numbers are not of the same length, so you get "unpredictable" results.
But if you adjust/filling the strings with zeros so they have the same length, it should work.
set "strBKSize=000000000000000000%bkSize%"
set "strBKSize=%strBKSize:~-15%"
set "strDisksize=000000000000000000%Disksize%"
set "strDisksize=%strDisksize:~-15%"
Or you try to calculate not with bytes, but in MB or GB, by removing 6 or 9 numbers/characters.
set BKFsizeGB=%BKFsize:~0,-9%
Then you can use them as numbers.
Maybe the values contained in your variables are not integers but strings
I suppose it's comparing: 8<3 == false
On windows, how could I open a dired buffer showing all drive letters. When you do C-x d you should always provide a directory, but I want to start at the drive letters level instead of a root directory of a particular drive.
If no standard solution exists, do you have one (an extension to dired ?) ? or links to articles on the subject ?
In dired you can only view directories, and since no directory exists which contains your drive letters, you can't see a list of them.
To do this you'd have to write an emacs-lisp extension for dired.
AFAIK there's no existing extension, however, a call to wmic can give you a listing of drive letters and volume names, which would be a good starting point.
The wmic command:
wmic logicaldisk get caption,drivetype,providername,volumename
Calling it from emacs-lisp and getting the result as a string.
(let (sh-output volumes)
(setq sh-output (shell-command-to-string "wmic LogicalDisk get Caption,DriveType,ProviderName,VolumeName"))
)
Will give you a list of the volumes (DriveType : 3 = HDD, 4 = Network Mapping, 5 = Optical.)
However, you can't get dired to recognize a buffer with this output, so you'd need to create a major mode for browsing windows volumes, which would show this listing and bind RET to find the drive letter on the current line and do a dired at it's root.
If you just want the drive letters listed...
(let (sh-output volumes)
(setq sh-output (shell-command-to-string "wmic LogicalDisk get Caption"))
)
Will do that.
Dired+ has what you want.
Command diredp-w32-drives opens a list/menu of the Windows drives. Use RET or mouse-2 to open Dired on one of the drives. The local drives come from option diredp-w32-local-drives, which you can customize.
If you hit ^ in Dired when visiting one of your drives (e.g. C:\), then you get to the same list/menu of all drives.
I'm trying to figure out the available disk space programmatically in windows. For this, I need to first get a list of the available drives, then check which of those are local drives and then query the available bytes on each local drive.
I'm a bit stuck on the first part, where the API presents two functions:
GetLogicalDrives (http://msdn.microsoft.com/en-us/library/aa364972(VS.85).aspx) which gives you a DWORD with the bits set (bit 0 if drive A is present, bit 1 if drive B etc)
GetLogicalDriveStrings (http://msdn.microsoft.com/en-us/library/aa364975(VS.85).aspx) which gives you the actual strings.
Now, although I'll be using strings later on, I'd prefer using the first option for querying. However, on my system a DWORD is typedef-ed to "unsigned long", which is 4 bytes, whereas drive letters only range A-Z (26 - i think - characters). Obviously, one can define more than 26 drives on their system (however unlikely they are to do so) - so I was wondering if there was any convention for those drives. Can someone point me to a resource on this?
Thanks.
DWORD is always 4 bytes, regardless of the system (it's a Win32 type).
The maximum for drive letters in Windows is 26. Because English alphabet has only 26 letters :). However, Windows allows two ways to mount a volume:
to a drive letter
to a directory (on an NTFS volume).
You can mount one volume to multiple locations (but no more than one drive letter, IIRC). A GUI for this task is presented by Control Panel -> Administrative Tools -> Computer Management -> Disk Management.
If you want to have more than 26 drives with the additional drives being redirects to already active drives and are okay with them not working properly in most programs, then you can assign more with the following method (be warned they won't even show up in the file explorer):
subst ♪: C:\Temp\
cd /D ♪:\
and to delete them (also they aren't preserved through restarts):
subst /D ♪:
You can enumerate all volumes and their mount points as described in this article.
You could use WMI. The following WMI query should list all drives:
SELECT * FROM Win32_DiskDrive
It it not sufficient to enumerate MS-DOS drives (there can be at most 26 of them, by the way, although each can be bound twice, once globally and once locally in your session), a volume can, for example, be mounted to a directory. What you want is probably to enumerate all volumes in the system, using FindFirstVolume et al. Take a look at the associated MSDN example.