"("を含むパス上にあるbatファイルを、「管理者として実行」で正常実行できない
質問
2011年6月13日月曜日 9:00
[現象]
"("を含むパス上にあるbatファイルを、「管理者として実行」で正常実行できない
[現象発生OS]
Windows7 SP1(32bit)
(WindowsVista/WindowsServer2008でも同じ現象が発生)
[現象再現手順]
(1)"c:\test(dir\test.bat" を作成
<test.batの内容>
pause
(2)エクスプローラでtest.batを選択し、右クリックで出るメニューから、
「管理者として実行(A)...」を選択。
(3)ユーザアカウント制御ダイアログボックスが表示される。「はい」を選択して続行。
(4)一瞬コマンドプロンプトが表示されるが、すぐに消える。
本来なら、pauseコマンドが実行され、「続行するには何かキーを押してください . . .」
が表示されキー入力待ち状態になるはず。
[試したこと]
(a)UAC有効/無効に関係なく、現象は同じ。
(b)"c:\test(dir\test.bat" を単純にダブルクリックとして実行すると、正常に実行される。
(c)test.batをc:\testdir\配下に置くと、「管理者として実行(A)...」でも正常に実行される。
=>いろいろパスを変えて試したが、"("を含むパスだと今回の現象が発生。
[知りたいこと]
特に回避策は望まないが、何故このような現象が発生するのか、理由を知りたい。
すべての返信 (7)
2011年6月13日月曜日 9:59 ✅回答済み | 1 票
「管理者として実行 」をbatファイルに対して実行しようとすると、通常は
%SystemRoot%\System32\cmd.exe /C "バッチファイル.bat"
が実行されます。
#レジストリのHKEY_CLASSES_ROOT\batfile\shell\runas\commandで指定されてます。
このCmd.exeのヘルプをコマンドラインでCmd.exe /?で表示させてみると以下の記述があります。
引用開始
/C または /K が指定されている場合、スイッチの後の残りのコマンド ラインが コマンド ラインとして処理されます。次のルールが引用符 (") の処理に使われます: 1. 次のすべての条件に一致する場合、コマンド ラインの引用符が有効になり ます: - /S スイッチがない - 引用符が 1 組ある - 引用符の中に特殊文字がない (特殊文字は &<>()@^| です) - 引用符の中に 1 つ以上のスペースがある - 引用符の中の文字列が、実行可能ファイルの名前である
引用ここまで
つまり、特殊文字に該当するためにCmd.exeはバッチファイルをを実行せずに終了します。
#たぶん「管理者として実行 」のバグとは言い切れないけど、想定外の挙動だと思います。
cmd.exe の引数にするときは特殊文字をエスケープする(特殊文字の前に^を追加する)ので回避策できるみたいですが、わざわざエスケープするぐらいなら名前を変更しますよね。(^^
2011年6月14日火曜日 14:20 ✅回答済み | 1 票
(1)「管理者として実行 」すると今回の現象が発生するのに、単純にダブルクリック
して実行すると、正常に動作するのは何故か?
ダブルクリックして開く場合は、open\command にどういったコマンドが実行されるかが書いてあります。
runas\command と見比べてみてください。
=>例えば、私が作成したbatファイルを誰かに提供し、「好きなフォルダにコピーして使用して
ください」とは言えなくなります。「"("などを含まないパス上に置いてください」という注釈を
つける必要がでてきます。
注釈をつけざる得ない点は仕方ないと考えます。
管理者として実行することを求めている以上、何か言及されるドキュメントがあるのですよね?
そうであれば、そこに一緒に書くことでしょうか。
# bat を実行するダミー exe とかも考えられますが、ちょっとナンセンスかな。
(3)gekka様は「たぶん「管理者として実行 」のバグとは言い切れないけど、想定外の挙動」
と書かれてますが...この現象はやっぱり不具合であると思います。
(略)
=>しかし、エクスプローラからメニューを選らんで実行するのに、パス上に特殊文字があるか
どうかによって実行できないのは、エクスプローラの不具合だと思います。
想定外の挙動であり、不具合でしょう。
エクスプローラーの不具合と言うよりは、Windows の不具合ですね。
(関連づけのレジストリ構造自体、エクスプローラー以外からも利用できるため)
ただ、すぐには直らないと思いますし、もしかしたらずっと直らないかもしれません。
直してほしいとアピールしつつ、注釈をつけるしかないと思います。
# runas\command を書き換えるのは微妙だし。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
2011年6月15日水曜日 3:51 ✅回答済み | 2 票
結局、cmd.exeを経由するかどうかの違いと解釈しました。
open/commandのときもcmd.exeによって*.batファイルは実行されます。
いろいろ調べた結果
- open/commandのとき、%1には""で囲ったパスが入る。
- runas/commandのときは、%1には""で囲っていないパスが入る。
という挙動をすることがわかりました。
これは、「管理者として実行」するときは通常はexeファイルが対象になるので、HKEY_CLASSES_ROOT\exefile\shell\runas\commandの「"%1" %*」に囲っていないパスを入れることに合わせた挙動と思われます。
runas/commandのときは1重で囲ってあるので特殊文字の影響を受けてしまいます。
open/commandはパスが2重に""で囲うことになるために、特殊文字をエスケープしなくとも正しいパスとして処理されているようです。この挙動はcmdのヘルプの
2. 最初の文字が引用符であるにも関わらず上の条件に一致しない場合は、最初 の引用符とコマンド ラインの最後の引用符が削除され、最後の引用符の後 のテキストが有効になります。
が適用されている(?)のかもしれません。
現状の挙動が正常であるとすると
"%SystemRoot%\System32\cmd.exe" /C ""%1"" %*
となっているのが正しい設定ということになりそうです。
2011年6月14日火曜日 4:47
gekka様、返信ありがとうございました。
当方は、Linuxなどの経験はあるものの、Windowsでの経験が乏しく、レジストリ周り
などは殆ど知りませんでした。
「管理者として実行 」時の処理が、HKEY_CLASSES_ROOT\batfile\shell\runas\command
で指定されている件、了解しました。
また、そこに「%SystemRoot%\System32\cmd.exe /C "%1" %*」と記述されているので、
cmd.exe経由でbatファイルが実行される、それゆえcmd.exeの引数の解釈方法により、
今回の現象が発生している、という点も了解しました。
しかし、次のような疑問も発生しました。
(以下の点は、あらたな疑問というよりは、gakka様の返信をヒントに調査すべき点と
してまとめました)
=====================================================
(1)「管理者として実行 」すると今回の現象が発生するのに、単純にダブルクリック
して実行すると、正常に動作するのは何故か?
=>たぶん、「単純にダブルクリックした場合は、cmd.exeを経由しない」というのが
理由と推測しますが...
=>単純にダブルクリックした場合にも、レジストリのどこかの設定に書かれていて、
それが実行されるのか、といった点を調査したいと思います。
=>Linuxなどの経験からすると、やや不思議な気がします。
batファイルはLinuxでいえばshスクリプトに当たると思います。
これを解釈するプログラムがcmd.exe(Linuxならばbashなどのshell)だとすれば、
batファイルを実行する場合には、常にcmd.exeが動きそうなものですが、
「管理者として実行 」のときのみcmd.exeが動く、というのは何故なのか
理解できませんでした。
(2)「cmd.exe の引数にするときは特殊文字をエスケープする(特殊文字の前に^を追加する)ので回避策できる」
=>この点は理解できるのですが...例えばこれが「ファイル名」のみの問題であったならば、
batファイルにそのような特殊文字を含まないファイル名をつければ解決します。
ただし、パス名に特殊文字を含む場合にも今回の現象が発生するのが問題です。
=>例えば、私が作成したbatファイルを誰かに提供し、「好きなフォルダにコピーして使用して
ください」とは言えなくなります。「"("などを含まないパス上に置いてください」という注釈を
つける必要がでてきます。
(3)gekka様は「たぶん「管理者として実行 」のバグとは言い切れないけど、想定外の挙動」
と書かれてますが...この現象はやっぱり不具合であると思います。
=>コマンドプロンプトを開き、そこでcmd.exeを使用するのならば、cmd.exeに与える引数に
特殊文字が含まれている場合にはエスケープする、というのは使用側の責任だと思います。
=>しかし、エクスプローラからメニューを選らんで実行するのに、パス上に特殊文字があるか
どうかによって実行できないのは、エクスプローラの不具合だと思います。
=>OS提供側からは、「いや、それはエクスプローラの不具合でなくcmd.exeの仕様で...」
という反論があるかも知れません。しかし、使用者側から言わせれば、
「cmd.exeがそういう仕様ならば、何故エクスプローラで特殊文字を含むパスをエスケープして
からcmd.exeに渡さないのか」
となります。
使用者側は、右クリックして出るメニューから「cmd.exeで実行」を選んでいるのではなく、
「管理者として実行」を選んでいるのですから。「管理者として実行」でcmd.exeが実行される
のは、あくまでOS内部の事情に過ぎません。
=====================================================
以上、宜しくお願い致します。
2011年6月15日水曜日 2:27
Azulean様、返信ありがとうございます。
>ダブルクリックして開く場合は、open\command にどういったコマンドが実行されるかが書いてあります。
>runas\command と見比べてみてください。
はい。ここは見てみました。
open\command: "%1" %*
runas\command: %SystemRoot%\System32\cmd.exe /C "%1" %*
結局、cmd.exeを経由するかどうかの違いと解釈しました。
>想定外の挙動であり、不具合でしょう。
>エクスプローラーの不具合と言うよりは、Windows の不具合ですね。
>(関連づけのレジストリ構造自体、エクスプローラー以外からも利用できるため)
>
>ただ、すぐには直らないと思いますし、もしかしたらずっと直らないかもしれません。
>直してほしいとアピールしつつ、注釈をつけるしかないと思います。
最初の投稿に書いたように、理由が知りたかっただけですので...
直るのはあまり期待していません。不具合や不具合とは言えなくても妙な挙動はこれ以外にも多いですし。
batファイルを配布する際に、注釈をつけようと思います。
理由が分かったので、すっきりしましたし、勉強になりました。
gekka様、Azulean様、ありがとうございました。
2011年6月15日水曜日 6:58 | 1 票
gekka様、返信有難う御座いました。
> open/commandのときもcmd.exeによって*.batファイルは実行されます。
うっ...やはりですか...
直前の投稿では
「cmd.exeを経由するかどうかの違い」
と書きましたが、
その前の投稿で書いたように、
「batファイルを実行する場合には、常にcmd.exeが動きそうなもの」
という思いもあったので、その辺をちょっと調べておこうとは思っていたのですが...
> いろいろ調べた結果
> open/commandのとき、%1には""で囲ったパスが入る。
> runas/commandのときは、%1には""で囲っていないパスが入る。
> という挙動をすることがわかりました。
これは意外でした。
> これは、「管理者として実行」するときは通常はexeファイルが対象になるので、HKEY_CLASSES_ROOT\exefile\shell\runas\commandの「"%1" %*」に囲っていないパスを入れることに合わせた挙動と思われます。
>
> runas/commandのときは1重で囲ってあるので特殊文字の影響を受けてしまいます。
> open/commandはパスが2重に""で囲うことになるために、特殊文字をエスケープしなくとも正しいパスとして処理されているようです。この挙動はcmdのヘルプの
>
> 2. 最初の文字が引用符であるにも関わらず上の条件に一致しない場合は、最初
> の引用符とコマンド ラインの最後の引用符が削除され、最後の引用符の後
> のテキストが有効になります。
> が適用されている(?)のかもしれません。
なるほど...
ちなみに、「最初の文字が引用符であるにも関わらず上の条件に一致しない」というのは、
"("があるので、「引用符の中に特殊文字がない」という条件に引っ掛かる、ということですね。
> 現状の挙動が正常であるとすると
> "%SystemRoot%\System32\cmd.exe" /C ""%1"" %*
> となっているのが正しい設定ということになりそうです。
ご指摘のように、HKEY_CLASSES_ROOT\batfile\shell\runas\command を
「"%SystemRoot%\System32\cmd.exe" /C "%1" %*」
から
「"%SystemRoot%\System32\cmd.exe" /C ""%1"" %*」
に変更したら...
"("を含むパス上にあるbatファイルを、「管理者として実行」で正常に実行できました!
また、(当然かもしれませんが)"("を含まないパス上にあるbatファイルも正常に実行できる
ことを確認しました。
今回の現象の理由が分かり、回避策も分かりました。
しかし、レジストリの変更は避けたいので、batファイルの配布先でレジストリ変更
して対処して貰うことはせず、注釈のみに留めたいと思います。
gekka様、いろいろ教えて戴き、調査もして下さり、本当に有難う御座いました。
私にとっても非常に勉強になりました。
2013年2月10日日曜日 6:48
"%SystemRoot%\System32\cmd.exe" /C ""%1"" %*
理屈の上では、引数に引用符がある場合、そちらの引用符が削除されます。
""name"" "arg" → "name"" "arg
なので、
"%SystemRoot%\System32\cmd.exe" /C ""%1" %*"
のほうがよいでしょう。
更に、
"%SystemRoot%\System32\cmd.exe" /S /C ""%1" %*"
としたほうが、明示的でよいでしょう。
別のやり方としては
"%SystemRoot%\System32\cmd.exe" /C call "%1" %*
が使えるのではないかと思います。