はじめに
バッチスクリプトで音声ファイルを一括処理していると、ショートカット(.lnk)ファイルもまとめて処理したいと感じる場面が出てくる。
たとえば、作業用フォルダに .mp3 や .ogg と並んで .lnk が混在しているケースだ。
しかし、バッチファイルは .lnk を実体ファイルとして解釈できない。そのまま *.lnk を処理対象に含めると、ツール側でエラーが発生しやすい。
この記事では、opus コマンドを用いた音声変換バッチを例に、.lnk を正しく展開して処理対象に含める方法を解説する。
古い手法に頼らず、現在でも安定して動作する実装に焦点を当てる。
なぜ .lnk はそのまま扱えないのか
.lnk ファイルは実体ファイルではない。
中身は「リンク先のパス」「起動オプション」「作業ディレクトリ」などを格納したバイナリ形式のショートカット情報である。
そのため、
dirやfor %%f in (*.lnk)で列挙はできる- しかし、そのパスをそのままエンコーダや変換ツールに渡すと失敗する
という挙動になる。
重要なのは、.lnk を一度「リンク先の実ファイルパス」に変換する工程が必要という点だ。
.lnk を処理可能なパスに変換する
方法1:WScript.Shell を使ってターゲットパスを取得する(推奨)
現在でも最も安定している方法は、WScript.Shell の CreateShortcut を使う手法だ。
PowerShell を使わず、純粋なバッチから呼び出せる点が強みになる。
以下は、.lnk を含む音声ファイルを再帰的に処理し、opus で変換する例だ。
修正後のバッチスクリプト例
@echo off
>nul 2>&1 chcp 65001
for /f "delims=" %%a in ('dir /b /s /a:-d *.mp3 *.ogg *.m4a *.wav *.flac *.wv *.lnk') do (
call :process "%%~a"
)
goto :eof
:process
set "fp=%~1"
set "nm=%~n1"
set "xt=%~x1"
:: .lnk の場合はリンク先を解決
if /i "%xt%"==".lnk" (
for /f "delims=" %%A in ('
mshta.exe "javascript:
var sh=new ActiveXObject('WScript.Shell');
var lnk=sh.CreateShortcut('%fp:\=\\%');
var fso=new ActiveXObject('Scripting.FileSystemObject');
if(fso.FileExists(lnk.TargetPath))
WScript.Echo(lnk.TargetPath);
close();"
') do (
set "fp=%%~fA"
set "nm=%%~nA"
)
)
:: opus 変換処理
opus ^
-y -i "%fp%" ^
-af dynaudnorm=p=0.65:m=2:f=200:g=15:s=30 ^
-c:a libopus -b:a 128k -vn ^
"F:\JDownloader\Musik Alben\xoutput\%nm%_dyn.ogg"
goto :eof
この実装のポイント
- 拡張子が
.lnkの場合のみ処理を分岐 mshta.exeから JScript を実行し、WScript.Shell.CreateShortcut()を利用TargetPathの存在確認を行い、不正なリンクを回避- 実体ファイルのパスに差し替えたうえで
opusを実行
この方法は Windows 10 / 11 の標準構成で動作し、.lnk の仕様変更の影響も受けにくい。
方法2:type コマンドを使う簡易的な方法(非推奨)
一見すると簡単に見えるのが、type と find を組み合わせる方法だ。
for /f "delims=" %%a in ('type "sample.lnk" ^| find ":\"') do set TARGET=%%a
echo %TARGET%
.lnk 内に含まれるパス文字列を拾い出すという発想になる。
ただし、この方法には明確な問題がある。
.lnkはバイナリ形式であり、構造が保証されていない- パスが複数含まれる場合、誤検出の可能性がある
- UNC パスや相対パスでは失敗しやすい
検証用途なら使えるが、実運用には向かない。
まとめ
バッチスクリプトで .lnk を処理対象に含める場合、リンク先の実体パスを取得する工程が不可欠となる。
選択肢は大きく2つある。
- WScript.Shell を使って正式にリンク先を解決する方法
- 動作が安定している
- Windows 標準機能のみで完結する
- 実運用向き
- type コマンドで文字列を抜き出す方法
- 実装は簡単
- 再現性が低く、環境依存が大きい
音声変換やメディア処理のように失敗が許されないバッチでは、前者一択だ。
.lnk を「ただのファイル」と誤解しないこと。
一段階展開する、そのひと手間がスクリプト全体の安定性を大きく引き上げる。
実際の運用環境に合わせて、ぜひ組み込んでほしい。

コメント