概要
bat → powershell → cmd → mklink の流れでシンボリックリンクを作った直後に、
bat内でシンボリックリンクの存在確認(if exist)すると「存在しない」(false)になってしまうことがありました。
powershell.exe の引数に -Wait
を入れて cmd の完了を待てば解決しました。
存在確認(if exist)すると「存在しない」(false)になった実装
※ 環境によるかもしれない。
check_symbolic_link.bat
@echo off
set TARGET="C:\workspace\to_dir"
set SOURCE="D:\from_dir"
REM シンボリックリンクがある場合は削除する
if exist %TARGET% (
rmdir %TARGET%
echo %TARGET% を削除
)
echo シンボリックリンク %TARGET% を作る
powershell.exe -Command Start-process "cmd" -ArgumentList "/C", "mklink", "/D", %TARGET%, %SOURCE% -Verb Runas
REM シンボリックリンクをチェックする
if exist %TARGET% (
echo %TARGET% がある
) else (
echo %TARGET% がない
)
check_symbolic_link.bat
を実行してみます。
> check_symbolic_link.bat
"C:\workspace\to_dir" を削除
シンボリックリンク "C:\workspace\to_dir" を作る
"C:\workspace\to_dir" がない
なんと「"C:\workspace\to_dir" がない」 が出力される。
※ if exist %TARGET% がfalseになってしまう。。。
原因の推測
powershellはcmdを起動できたら batに制御を戻してしまう様子。
そのおかげで、batがmklinkの完了前にさっさとif existで確認してしまうから
・・・だと思われる
対策
powershell.exe の引数に -Wait
を入れると「起動するプロセスが終了するのを待つ」動作になるので、それを利用します。
副作用でpowershellから起動したcmdの画面が見えてしまうが、if existが安定したのでOKとした。
check_symbolic_link_fix.bat
@echo off
set TARGET="C:\workspace\to_dir"
set SOURCE="D:\from_dir"
REM シンボリックリンクがある場合は削除する
if exist %TARGET% (
rmdir %TARGET%
echo %TARGET% を削除
)
echo シンボリックリンク %TARGET% を作る
powershell.exe -Command Start-process "cmd" -Wait -ArgumentList "/C", "mklink", "/D", %TARGET%, %SOURCE% -Verb Runas
REM シンボリックリンクをチェックする
if exist %TARGET% (
echo %TARGET% がある
) else (
echo %TARGET% がない
)
check_symbolic_link_fix.bat
を実行してみます。
>check_symbolic_link_fix.bat
"C:\workspace\to_dir" を削除
シンボリックリンク "C:\workspace\to_dir" を作る
"C:\workspace\to_dir" がある
安定して "C:\workspace\to_dir" がある・・・となった。
参考
管理者権限でbatを実行したい時にやッた事 - Qiita
Windowsでシンボリックリンク作成@非管理者権限環境 - Qiita