Сопоставление сетевого диска без жесткого кодирования буквы диска в командном файле

Мне нужно сопоставить сетевой диск с командным файлом, но я не хочу указывать букву диска.

Пакетный файл используется как часть процесса развертывания; Я вызываю командный файл из 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

7 ответов

Решение

Если у вас нет нескольких сетевых ресурсов, подключенных одновременно, вы можете сделать 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

РЕДАКТИРОВАТЬ:

Как я узнал из некоторых исследований, вы можете просто сопоставить общий ресурс, не назначая букву диска. Затем он отображается анонимно, только по удаленному 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

Я использую это, чтобы позволить 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 Команда на UNC-путь, который существует наверняка, поэтому создается временная буква диска, которая указывает на этот путь. Текущий каталог, а именно корень временного диска, может быть определен для получения буквы диска. Наконец, popd Команда должна использоваться для удаления временной буквы диска:

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%`.

Переменная COMPUTERNAME и доля \\%COMPUTERNAME%\ADMIN$ должен существовать во всех современных (основанных на NT) системах Windows.


Если вы не хотите, чтобы текущая среда даже временно "загрязнялась" при попытке pushd Чтобы получить букву свободного диска, вы можете использовать следующий подход:

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%`.

Хорошо... это не может быть гламурно, но именно так я сейчас и делаю; базовый подход попытки поймать. Попробуйте подключить диск и, если он используется, перейдите к следующему шагу. Я проиллюстрировал это всего двумя попытками, но нетрудно расширить его до 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

Самый простой метод:

pushd "\\server\share\wwwroot\My Project"
robocopy . x:\ *.* /E ...etc
popd

Pushd автоматически сопоставит сетевой диск с доступной буквой, а popd удалит его. Это внутренние команды CMD; использование путей 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>

@longneck, я использую что-то вроде этого:

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

Это позволяет избежать второго вызова net по каналу 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

Подпрограмма разбора здесь не очень полезна и только иллюстрирует концепцию.

Другие вопросы по тегам