Batch file 映射网络驱动器而不在批处理文件中硬编码驱动器号

Batch file 映射网络驱动器而不在批处理文件中硬编码驱动器号,batch-file,network-drive,Batch File,Network Drive,我需要用批处理文件映射网络驱动器,但不想指定驱动器号 @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 P

我需要用批处理文件映射网络驱动器,但不想指定驱动器号

@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
批处理文件用作部署过程的一部分;我从
CruiseControl.Net
调用批处理文件,批处理文件需要映射一个需要凭据进行身份验证的UNC路径。然后批处理文件调用
RoboCopy
,将网站从输出目录部署到目标目录(并排除一些文件和文件夹)。最后,批量删除网络驱动器

问题是,这是不可伸缩的,当只有几个项目时,这是可以的,但我们现在有20个项目使用这种方法,并且正在耗尽要映射的驱动器号。我不想重复使用驱动器号,因为它们可能会发生碰撞,这是很糟糕的

这是批处理文件的一个示例:

@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
并格式化为可读性:

@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

如果您没有同时连接多个网络共享,您可以让
net use*
为您分配一个免费驱动器号。之后,您可以使用
robocopy
通过其UNC路径访问共享,并使用
net use*/delete
释放任何连接的共享

大概是这样的:

@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
for /f "tokens=2" %%i in ('net use * \\server\share') do (
    if defined netdrive goto :cont
    set netdrive=%%i
)

:cont
echo.%netdrive% has been mapped
pause

net use %netdrive% /d /y
pause
编辑:

正如我从一些研究中了解到的,您可以简单地映射共享,而无需指定驱动器号。然后,仅通过其远程UNC路径对其进行匿名映射。通过这种方式,还可以通过仅指定映射的远程名称来删除映射

这应该起作用:

@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

好的。。。这可能并不迷人,但我现在就是这样做的;一种基本的尝试-抓住方法。尝试映射驱动器,如果正在使用,则转到下一步。我只尝试了两次就说明了这一点,但将其扩展到4、10或更多驱动器号并不困难

是的,它确实冒犯了我的编程敏感性,我不喜欢重复代码。不幸的是,我不知道如何将路径和凭据传递到批处理文件中,因为我自己不调用它,CruiseControl.net调用它时没有参数

@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

我使用此选项让NET选择一个空闲驱动器盘符,然后使用NET找出它分配的盘符:

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

有些人可能会发现以下批处理文件很有用

它不依赖于外部程序

批处理文件包含一个函数
:freedrive
,用于查找可用驱动器号并将其返回到变量中。它还可以正确地检测没有介质的光盘驱动器是否占用驱动器盘符

@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
最简单的方法:

pushd "\\server\share\wwwroot\My Project"
robocopy . x:\ *.* /E ...etc
popd
将自动将网络驱动器映射到可用的字母,并将其删除。它们是内部命令;使用UNC路径需要启用扩展。批处理示例:

@echo off
pushd %1
  echo. --- Processing %1 as "%cd%"
  echo. ...
  rem do thing here
  echo. Done.
popd
注意:在这个使用命令行参数的实现中,命令行上的路径必须被引用

示例会话:

E:\temp>.\demo-pushd.bat "\\server\share\wwwroot\My Project"
 --- Processing "\\server\share\wwwroot\My Project" as "X:\wwwroot\My Project"
    ...
    Done.

E:\temp> net use X:
The network connection could not be found.

More help is available by typing NET HELPMSG 2250.
E:\temp>

@长颈鹿,我用的是这样的东西:

@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
for /f "tokens=2" %%i in ('net use * \\server\share') do (
    if defined netdrive goto :cont
    set netdrive=%%i
)

:cont
echo.%netdrive% has been mapped
pause

net use %netdrive% /d /y
pause
这避免了通过find对网络管道的第二次调用

您还可以在此基础上进行扩展,这样就不用直接调用set netdrive,而是在一个子例程中进行。这允许您进行更多的错误检查或处理

for /f "tokens=2" %%i in ('net use * \\server\share') do (
    if defined netdrive goto :cont
    call :parse %%i
)

:parse
if ~%1==%1~ goto :eof
if Z:==%1 (
    set netdrive=%1
)
goto :eof

:cont
echo.%netdrive% has been mapped
pause

net use %netdrive% /d /y
pause

这里的parse子例程不是非常有用,只是说明了这个概念。

一个可能的解决方案是将应用于确实存在的UNC路径,因此创建一个指向该路径的临时驱动器号。可以确定当前目录,即临时驱动器的根目录,以获取驱动器号。最后,必须使用该命令删除临时驱动器号:

pushd“\\%COMPUTERNAME%\ADMIN$”
rem/*使用临时创建的驱动器的根在此处执行操作
rem用作当前工作目录*/
rem//将当前驱动器存储在变量'drive'中,以备以后使用:
对于/F“delims=:”(“%CD%”)中的%%D,请设置“驱动器=%%D:”
邻苯二胺
回显下一个可用驱动器号为“%drive%”。
变量
COMPUTERNAME
和共享
\\\%COMPUTERNAME%\ADMIN$
应存在于所有现代(基于NT的)Windows系统上


如果您不希望当前环境因尝试使用
pushd
获取免费驱动器号而被暂时“污染”,您可能需要使用以下方法:

对于/F“delims=:”%%D in('
pushd“\\%COMPUTERNAME%\ADMIN$”^&^
对于%%Z in^(.^)执行popd
“)是否设置“驱动器=%%D:”
回显下一个可用驱动器号为“%drive%”。

有可能同时连接多个网络共享,否则我可以为每个项目分配Z:或硬编码字母。net use*/delete还将释放所有连接的共享,这将是服务器上的一个问题,比我的解决方案要好得多:)
net use/删除
似乎不会立即清除凭据。在调用robocopy后,对已认证的位置运行robocopy仍然有效,直到进程退出。这似乎起到了作用,但可能有点过头了。没有办法按照OP的要求定义凭据。@thomas:今天这里的6个答案中只有2个说明了凭据的使用,但这是唯一值得否决的答案?使用pushd而不是For循环更直接、更简单,因为它解决了部分问题。其他答案使用
net
命令。虽然它们没有说明如何使用凭据,但至少是可能的;不是“检查什么可用并使用它”,而是“使用它并看看它是否有效”。