web-dev-qa-db-ja.com

バッチファイルでドライブ文字をハードコーディングせずにネットワークドライブをマッピングする

ネットワークドライブをバッチファイルにマップする必要がありますが、ドライブ文字を指定したくありません。

バッチファイルは、展開プロセスの一部として使用されます。 CruiseControl.Netからバッチファイルを呼び出します。バッチファイルは、認証に資格情報を必要とするUNCパスをマップする必要があります。次に、バッチファイルはRoboCopyを呼び出して、Webサイトを出力ディレクトリから宛先に展開します(一部のファイルとフォルダーは除外されます)。最後に、バッチはネットワークドライブを削除します。

問題は、これがスケーラブルではないことです。プロジェクトが少数の場合は問題ありませんが、このアプローチを使用してプロジェクトが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
15
Simon Martin

複数のネットワーク共有を同時に接続していない場合は、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
32
Frank Bollack

これを使用して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
11
longneck

一部のユーザーは、次のバッチファイルが役立つ場合があります。

外部プログラムには依存しません。

バッチファイルには関数: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
5
Jelle Geerts

OK ...これは魅力的ではないかもしれませんが、これは私が今これをやっている方法です。基本的なトライキャッチアプローチ。ドライブをマップしてみてください。ドライブが使用中の場合は、次のステップに進んでください。これを2回の試行で説明しましたが、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
2
Simon Martin

考えられる解決策は、確実に存在するUNCパスに pushdコマンド を適用することです。そのため、そのパスを指す一時的なドライブ文字が作成されます。現在のディレクトリ、つまり一時ドライブのルートは、ドライブ文字を取得するために決定できます。最後に、 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%`.
1
aschipfl

最も簡単な方法:

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>
0
matt wilkie

@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

これにより、findを介してパイプされるnetへの2番目の呼び出しが回避されます。

これを拡張して、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

ここでの構文解析サブルーチンはそれほど有用ではなく、概念を説明するだけです。

0
Ryan Beesley