Mapping a network drive without hardcoding a drive letter in a batch file

80,478

Solution 1

If you don't have multiple network shares connected simultaniously, you can make net use * assign a free drive letter for you. Afterwards you can use robocopy to access the share via its UNC path and release any connected share with net use * /delete.

Something like this:

@echo off
net use * \\192.168.0.1\Share\wwwroot\MyProject /user:mydomain\myuser MyP455w0rd
robocopy.exe "W:\wwwroot\MyProject" "\\192.168.0.1\Share\wwwroot\MyProject" *.* /E /XO /XD "App_Data/Search" "*.svn" /XF "sitefinity.log" "Thumbs.db" /NDL /NC /NP
net use * /delete /yes

EDIT:

As I learned from some researches, you can simply map the share without assigning a drive letter. It is then mapped anonymously, only by its remote UNC path. This way you can also remove the mapping by specifiying only its remote name.

This should work:

@echo off
net use \\192.168.0.1\Share\wwwroot\MyProject /user:mydomain\myuser MyP455w0rd
robocopy.exe "W:\wwwroot\MyProject" "\\192.168.0.1\Share\wwwroot\MyProject" *.* /E /XO /XD "App_Data/Search" "*.svn" /XF "sitefinity.log" "Thumbs.db" /NDL /NC /NP
net use \\192.168.0.1\Share\wwwroot\MyProject /delete

Solution 2

i use this to let NET pick a free drive letter, then use NET to find out what letter it assigned:

net use * \\server\share
for /f "tokens=2" %%i in ('net use ^| find "\\server\share"') do set netdrive=%%i
echo %netdrive% has been mapped

Solution 3

Some may find the following batch file useful.

It does not rely on external programs.

The batch file contains a function :freedrive, which finds a free drive letter and returns it in a variable. It also correctly detects optical drives that have no media as occupying a drive letter.

@echo off
setlocal

call :freedrive mydriveletter && goto :cont
echo ERROR: No free drive letter found.
goto :exit
:cont
echo Found drive letter: %mydriveletter%

goto :exit

rem Finds a free drive letter.
rem
rem Parameters:
rem     %1 = Output variable name.
rem
rem Example:
rem     call :freedrive mydriveletter && goto :cont
rem     echo ERROR: No free drive letter found.
rem     goto :EOF
rem     :cont
rem     echo Found drive letter: %mydriveletter%
:freedrive
setlocal EnableDelayedExpansion
set exitcode=0
set "output_var=%~1"
for %%i 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 (
    set "drive=%%i:"
    rem If 'subst' fails, the drive letter is already in use.
    rem This way we can even detect optical drives that have a drive
    rem letter but no media in them, a case that goes undetected when
    rem using 'if exist'.
    subst !drive! %SystemDrive%\ >nul
    if !errorlevel! == 0 (
        subst !drive! /d >nul
        goto :freedrive0
    )
)
set exitcode=1
set drive=
:freedrive0
endlocal & set "%output_var%=%drive%" & exit /b %exitcode%

:exit
pause

Solution 4

Ok... this might not be glamourous but this is how I'm doing this now; a basic try catch approach. Try to map a drive and if it's in use then goto the next step. I've illustrated this with just 2 attempts, but it's not hard to extend it to 4, 10 or more drive letters.

Yes it does offend my programming sensibilities, I don't like the repetion of code. Unfortunately I don't know how I could pass the path and credentials into the batch file as I don't call it myself, CruiseControl.net calls it without parameters.

@echo off

:START
net use z: \\192.168.0.1\Share\wwwroot\MyProject /user:mydomain\myuser MyP455w0rd
if %ERRORLEVEL% ==2 goto Y
ROBOCOPY HERE
net use z: /delete
exit

:Y
net use y: \\192.168.0.1\Share\wwwroot\MyProject /user:mydomain\myuser MyP455w0rd
if %ERRORLEVEL% ==2 goto W
ROBOCOPY HERE
net use y: /delete
exit

:W
sleep 20
goto START

Solution 5

A possible solution is to apply the pushd command to a UNC path that exists for sure, so a temporary drive letter is created that points to that path. The current directory, namely the root of the temporary drive, can be determined to get the drive letter. Finally, the popd command must be used to delete the temporary drive letter:

pushd "\\%COMPUTERNAME%\ADMIN$"
rem /* Do stuff here with the root of the temporarily created drive
rem    used as the current working directory... */
rem // Store the current drive in variable `DRIVE` for later use:
for /F "delims=:" %%D in ("%CD%") do set "DRIVE=%%D:"
popd
echo The next free drive letter is `%DRIVE%`.

The variable COMPUTERNAME and the share \\%COMPUTERNAME%\ADMIN$ should exist on all modern (NT-based) Windows systems.


If you do not want the current environment to become even temporarily "polluted" by the attempt of pushd to derive a free drive letter, you may want to use the following approach:

for /F "delims=:" %%D in ('
    pushd "\\%COMPUTERNAME%\ADMIN$" ^& ^
        for %%Z in ^(.^) do popd
') do set "DRIVE=%%D:"
echo The next free drive letter is `%DRIVE%`.
Share:
80,478

Related videos on Youtube

Simon Martin
Author by

Simon Martin

Developer specialising in the Angle Brackets stuff (ASP.NET, Azure, and Web Tools).

Updated on July 09, 2022

Comments

  • Simon Martin
    Simon Martin almost 2 years

    I need to map a network drive with a batch file, but don't want to specify the drive letter.

    The batch file is used as part of a deployment process; I call the batch file from CruiseControl.Net, the batch file needs to map a UNC path which requires credentials to authenticate. Then the batch file calls RoboCopy to deploy the website from the output directory to the destination (and excludes some files and folders). Finally the batch deletes the network drive.

    The problem is that this isn't scalable, it's fine when there are only a few projects but we've now got 20 projects using this approach and are running out of drive letters to map. I don't want to re-use drive letters as they could collide - which would be bad.

    This is an example of the batch file:

    @echo off
    net use x: \\192.168.0.1\Share\wwwroot\MyProject /user:mydomain\myuser MyP455w0rd
    robocopy.exe "W:\wwwroot\MyProject" x:\ *.* /E /XO /XD "App_Data/Search" "*.svn" /XF "sitefinity.log" "Thumbs.db" /NDL /NC /NP
    net use x: /delete
    

    and formatted for readability:

    @echo off
    net use x: \\192.168.0.1\Share\wwwroot\MyProject 
        /user:mydomain\myuser MyP455w0rd
    robocopy.exe "W:\wwwroot\MyProject" x:\ *.* /E /XO /XD 
        "App_Data/Search" "*.svn" /XF "sitefinity.log" "Thumbs.db" /NDL /NC /NP
    net use x: /delete
    
  • Simon Martin
    Simon Martin over 13 years
    There is a chance of multiple network shares connected simultaniously, otherwise I could just always assign Z: or a hardcoded letter per project. net use * /delete will also release ALL connected shares and that would be an issue on the server
  • Simon Martin
    Simon Martin over 13 years
    that's a lot nicer than my solution :)
  • Thomas Weller
    Thomas Weller over 8 years
    There is no way of defining credentials as required by OP.
  • matt wilkie
    matt wilkie over 8 years
    @thomas: Only 2 of the 6 answers here today illustrate use of credentials, yet this is the only answer that's merits a downvote? Use of pushd instead of a For loop is much more direct and simple, for the portion of the problem it addresses.
  • Thomas Weller
    Thomas Weller over 8 years
    The other answers use the net command. Though they don't illustrate how to use credentials, it is at least possible.
  • Ben
    Ben almost 7 years
    I like this approach; not "check to see what's available and use it" but rather "use it and see if it worked".
  • jpmc26
    jpmc26 about 6 years
    net use ... /delete doesn't seem to clear out the credentials immediately. Running robocopy against a credentialed location still works after calling it until the process exits. klist purge seems to do the trick, but it might be overkill.