DOSコマンドで、好きな形式に「パスのコピー」する

# はじめに
メールやチャットなどで、電子ファイルをやり取りするとき、フォルダ／ファイルのパスを書くことは、多いと思います。

```
XXです。

ご依頼の件、以下に格納しました。
<file://\\hoge\temp>
例の件.xlsx

以上、よろしくお願いいたします。
```

Windowsには、[Shift]キーを押しながらフォルダ／ファイルを右クリックしたときのコンテキストメニューに「パスのコピー」というものがありますが、コピーする（クリップボードに入る）パスは`"[右クリックしたフォルダ／ファイルへのパス]"`なので、メールやチャットにそのまま貼ってもリンクにはならないという点で、残念でした。

それを解決するためのツール（実行形式）は既にあると思いますが、DOSコマンドで実現できれば、バッチファイルだけでなく、コンテキストメニューにも追加できるということで着手しました。

# 結論
今どき、誰もDOSコマンドを覚えたい、ということはないだろうと思うので、まずは結論です。
下記コードをバッチファイルにして、好きなフォルダ／ファイルをバッチファイルにD&Dすればよいです。

```bash
set /p <NUL="<file://%~1>" | clip
```

エクスプローラ上の全フォルダ／ファイルに対して、コンテキストメニューに追加するならば、下記をUTF-16 BOM有、CR+LFのテキストとして、拡張子regのファイルに保存し、（管理者として）実行すればよいです。
（要注意：下記の場合、キー「EzCopyPath」が既存だと、キーの内容を上書きしてしまうかと思います）

```
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\EzCopyPath]
@="EzCopyPath(&Z)"

[HKEY_CLASSES_ROOT\*\shell\EzCopyPath\command]
@="cmd /c set /p <NUL=\"<file://%1>\" | clip"

[HKEY_CLASSES_ROOT\folder\shell\EzCopyPath]
@="EzCopyPath(&Z)"

[HKEY_CLASSES_ROOT\folder\shell\EzCopyPath\command]
@="cmd /c set /p <NUL=\"<file://%1>\" | clip"

```

メニュー文言・ショートカットキーの部分は、好きに変えてください。
ダブルクォーテーション（拡張子regのファイル上は`\"`）で囲まれた中の文字列を変えれば、ExcelのHYPERLINK関数に合わせることも可能です。

# DOSコマンド詳細
- set
  - /pオプションは本来、ユーザー入力を変数に代入。（今回は代入先となる変数を省略）
  - NULを入力してあげることで、ユーザー入力を終わらせる。
  - /pオプションでの右辺は、ユーザーへの表示メッセージだが、ダブルクォーテーションで囲むために好きな文字を書ける。しかも、表示の時にはダブルクォーテーションが消える。
- clip
  - パイプや入力リダイレクトで渡した文字列をクリップボードに入れる。

# 終わりに
発展形として、割当てドライブをUNCパスに変換（例：`H:\` >> `\\Hoge\`）するもの、ファイルに対して以下のような2行を取得するもの、も作りました。

```
<file://[親フォルダへのパス]>
[右クリックされたファイル]
```

ご要望があれば、展開させていただきたいと思います。

## 追記（2022/3/16）
ご要望いただいたので、発展形を展開させていただこうと思います。

- 作った自分が若干忘れているので、以下の機能が全部載せから、下手に触れないです。
  - 割当てドライブをUNCパスに変換（例：`H:\` >> `\\Hoge\`）
  - 右クリックしたファイル/フォルダに対して、`<file://[親フォルダへのパス]\>\n[ファイル/フォルダ名]`取得
  - 取得後、同じ階層のファイル/フォルダに対して右クリックしていくと、`\n[ファイル/フォルダ名]`付け足し可能

regファイルにすると、こちら。

```
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\EzCopyPathIE_UNC]
@="EzCopyPath項目列挙 - UNCパス変換(&I)"

[HKEY_CLASSES_ROOT\*\shell\EzCopyPathIE_UNC\command]
@="cmd /c for /f \"tokens=*\" %%f in ('echo.\"%1\"') do (powershell -command \"$ErrorActionPreference = 'silentlycontinue'; Add-Type -Assembly System.Windows.Forms; $dat = [Windows.Forms.Clipboard]::GetText(); $src = \\\"%%~dpf\\\\\"; $unc = (Get-WMIObject -query 'Select * From Win32_LogicalDisk Where DeviceID=\\\"%%~df\\\" and DriveType = 4').ProviderName; if ($unc -ne $null) {$src = join-path $unc (split-path $src -NoQualifier)}; if (($dat.Contains($src + '>')) -And ($dat -match '>\\r\\n[^\\r\\n]')) {$out = $dat;} else {$out = \\\"^<file://$src^>`r`n\\\";}; $out += \\\"%%~nxf\\\"; write \\\"$out\\\";\" | clip)"

[HKEY_CLASSES_ROOT\Folder\shell\EzCopyPathIE_UNC]
@="EzCopyPath項目列挙 - UNCパス変換(&I)"

[HKEY_CLASSES_ROOT\Folder\shell\EzCopyPathIE_UNC\command]
@="cmd /c for /f \"tokens=*\" %%f in ('echo.\"%1\"') do (powershell -command \"$ErrorActionPreference = 'silentlycontinue'; Add-Type -Assembly System.Windows.Forms; $dat = [Windows.Forms.Clipboard]::GetText(); $src = \\\"%%~dpf\\\\\"; $unc = (Get-WMIObject -query 'Select * From Win32_LogicalDisk Where DeviceID=\\\"%%~df\\\" and DriveType = 4').ProviderName; if ($unc -ne $null) {$src = join-path $unc (split-path $src -NoQualifier)}; if (($dat.Contains($src + '>')) -And ($dat -match '>\\r\\n[^\\r\\n]')) {$out = $dat;} else {$out = \\\"^<file://$src^>`r`n\\\";}; $out += \\\"%%~nxf\\\"; write \\\"$out\\\";\" | clip)"

```

とても長い、command部分は改行やインデントを入れると、こうなっています。

```
cmd /c for /f "tokens=*" %%f in ('echo."%1"') do (
	powershell -command "
		$ErrorActionPreference = 'silentlycontinue';
		Add-Type -Assembly System.Windows.Forms;
		$dat = [Windows.Forms.Clipboard]::GetText();
		$src = \"%%~dpf\\";
		$unc = (Get-WMIObject -query 'Select * From Win32_LogicalDisk Where DeviceID=\"%%~df\" and DriveType = 4').ProviderName;
		if ($unc -ne $null) {$src = join-path $unc (split-path $src -NoQualifier)};
		if (($dat.Contains($src + '>')) -And ($dat -match '>\r\n[^\r\n]')) {
			$out = $dat;
		} else {
			$out = \"^<file://$src^>`r`n\";
		};
		$out += \"%%~nxf\";
		write \"$out\";
	" | clip
)
```