【bat】バッチファイルでUSBデバイス接続を検知して処理する方法

【bat】バッチファイルでUSBデバイス接続を検知して処理する方法 bat

USBデバイスを差し込んだ瞬間に自動でファイルをバックアップしたい、特定のUSBが接続されたときだけ処理を走らせたい――そんなニーズに応えるのが、バッチファイルを使ったUSBデバイス検知の自動化です。Windows標準のコマンドラインツールだけで、外部ライブラリなしにUSB接続イベントを捕捉できます。

USB検知の方法は大きく2種類あります。一定間隔でドライブ一覧を確認するポーリング方式と、Windowsのイベント通知を受け取るWMIイベント方式です。前者はバッチファイル単体で完結し、後者はPowerShellと組み合わせることでUSB接続の瞬間を即時に検知できます。

この記事では、wmicコマンドによる基本的なポーリング検知から、PowerShell WMIイベントによる即時検知、シリアルナンバーを使った特定デバイス限定処理、robocopyによる自動バックアップ、CSVログ記録まで、実践で使えるテンプレートを段階的に解説します。

スポンサーリンク

USB検知の2つのアプローチ比較

まず2種類の方式の特性を整理します。用途に応じて適切な方法を選んでください。

比較項目 ポーリング方式(wmic) WMIイベント方式(PowerShell)
検知タイミング ループ間隔に依存(数秒〜数十秒遅延) 接続の瞬間を即時検知
実装の複雑さ バッチのみで完結・シンプル PowerShell + バッチの組み合わせ
CPU負荷 間隔次第でやや高い イベント待機中はほぼゼロ
必要ツール wmic(Windows標準) PowerShell 2.0以上(Win7以降標準)
接続・取り外し検知 差分比較で両方検知可能 EventTypeで種別を区別
特定デバイス識別 ボリュームラベルで判定 シリアルナンバーで高精度識別
向いている用途 学習・簡易自動化・定期チェック 本番運用・セキュリティ管理・即時処理

ポイント:初めてUSB検知を実装するならポーリング方式から始めてください。構造がシンプルで動作を理解しやすく、改造もしやすいです。即時性が必要な場合やCPU負荷を抑えたい本番環境ではWMIイベント方式を採用してください。

方法1:wmicポーリングによる基本的なUSB検知バッチ

ポーリング方式の基本は「現在のドライブ一覧を取得し、前回と比較して差分を見つける」ことです。DriveType=2がリムーバブルドライブ(USBメモリ・外付けHDDなど)を意味します。

usb-monitor.bat:ポーリング基本形
@echo off
setlocal enabledelayedexpansion
set INTERVAL=5
set PREV="%TEMP%\usb_prev.txt"
set CURR="%TEMP%\usb_curr.txt"

rem 初回スナップショット
wmic logicaldisk where DriveType=2 get DeviceID /value | find "DeviceID" | sort > %PREV%
echo USB監視開始(間隔: %INTERVAL%秒)Ctrl+C で停止

:loop
ping -n %INTERVAL% 127.0.0.1 >nul
wmic logicaldisk where DriveType=2 get DeviceID /value | find "DeviceID" | sort > %CURR%

fc /b %PREV% %CURR% >nul 2>&1
if %ERRORLEVEL% neq 0 (
    echo [%time%] ドライブ変化を検知
    call :on_change
    copy /y %CURR% %PREV% >nul
)
goto loop

:on_change
rem ここに実行したい処理を記述する
echo USB変化を検知 - 処理を実行します
exit /b 0

注意:待機にtimeoutではなくping -n N 127.0.0.1を使っています。timeoutはタスクスケジューラ経由など非対話環境で動作しない場合があるため、pingによるウェイトが安定します。-n 5で約5秒待機します。

方法1:ドライブレターとボリュームラベルの取得方法

USB接続を検知したあと、どのドライブが接続されたか(ドライブレター)と、USBの名前(ボリュームラベル)を取得します。/format:csvを使うとカンマ区切りで出力されるため、for /fで各フィールドを分解しやすくなります。

ドライブレターとボリュームラベルの取得
@echo off
setlocal enabledelayedexpansion

rem skip=1でヘッダー行をスキップ、tokens=1,2でDeviceIDとVolumeName
for /f "skip=1 tokens=2,3 delims=," %%A in (
    'wmic logicaldisk where DriveType=2 get Caption,VolumeName /format:csv'
) do (
    if not "%%A"=="" (
        set DRIVE=%%A
        set LABEL=%%B
        echo ドライブ: !DRIVE!  ラベル: !LABEL!
    )
)
endlocal

方法1:差分検知で新規接続・取り外しを判定する

「変化があった」だけでなく、「どのドライブが新しく追加されたか」「どのドライブが取り外されたか」を個別に判定するには、前回・今回のドライブ一覧を比較します。

usb-diff.bat:新規接続・取り外しを個別検知
@echo off
setlocal enabledelayedexpansion
set PREV="%TEMP%\usb_prev.txt"
set CURR="%TEMP%\usb_curr.txt"
set INTERVAL=5

call :get_drives %PREV%

:loop
ping -n %INTERVAL% 127.0.0.1 >nul
call :get_drives %CURR%

rem 今回にあって前回にない → 新規接続
for /f "usebackq delims=" %%D in (%CURR%) do (
    find "%%D" %PREV% >nul 2>&1
    if %ERRORLEVEL% neq 0 (
        echo [%time%] 接続: %%D
        call :on_connect %%D
    )
)

rem 前回にあって今回にない → 取り外し
for /f "usebackq delims=" %%D in (%PREV%) do (
    find "%%D" %CURR% >nul 2>&1
    if %ERRORLEVEL% neq 0 (
        echo [%time%] 取り外し: %%D
        call :on_disconnect %%D
    )
)

copy /y %CURR% %PREV% >nul
goto loop

:get_drives
wmic logicaldisk where DriveType=2 get Caption /value | findstr "Caption" | sort > %1
exit /b 0

:on_connect
echo 接続処理: %1
exit /b 0

:on_disconnect
echo 取り外し処理: %1
exit /b 0

差分検知の仕組み

  • 現在のドライブ一覧に含まれるが前回にない → 新規接続(on_connectを呼ぶ)
  • 前回のドライブ一覧に含まれるが現在にない → 取り外し(on_disconnectを呼ぶ)
  • 比較後に現在のスナップショットを前回として保存し、次のループへ

方法1:接続時の自動処理テンプレート(ラベル判定・コピー・ログ)

差分検知で新規接続を捕捉したあとの、実用的な処理テンプレートです。ボリュームラベルで特定のUSBかどうかを判定し、ファイルコピーとログ記録を行います。

on_connect処理:ラベル判定+コピー+ログ記録
:on_connect
setlocal
set DRIVE=%1
set TARGET_LABEL=BACKUP_USB
set DEST=C:\Backup\USB
set LOG=C:\Backup\usb_log.txt

rem USB初期化待ち(接続直後は2秒ほど使えないことがある)
ping -n 3 127.0.0.1 >nul

rem volコマンドでボリュームラベルを取得
for /f "skip=1 tokens=5" %%L in ('vol %DRIVE%') do (
    set LABEL=%%L
    goto :got_label
)
:got_label

echo %date% %time%  接続  %DRIVE%  %LABEL% >> %LOG%

if /i "%LABEL%"=="%TARGET_LABEL%" (
    echo 対象USB検知: バックアップ開始
    if not exist "%DEST%" mkdir "%DEST%"
    xcopy "%DRIVE%\*" "%DEST%\" /e /y /q
    echo %date% %time%  完了  %DRIVE% >> %LOG%
) else (
    echo 対象外USB [%LABEL%] - スキップ
)
endlocal
exit /b 0

方法2:PowerShell WMIイベントで即時検知する仕組み

PowerShellのWin32_VolumeChangeEventはWindowsがドライブのマウント・アンマウント時に発行するイベントです。WaitForNextEvent()でイベントが来るまでスレッドをブロック待機するため、CPU使用率はほぼゼロです。

PowerShell:WMIイベント監視の基本形
# EventType=2(ドライブ追加)のみ受信するクエリ
$query   = "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2"
$watcher = New-Object System.Management.ManagementEventWatcher
$watcher.Query = New-Object System.Management.WqlEventQuery $query
$watcher.Start()

Write-Host "USB監視を開始しました(Ctrl+C で停止)"

try {
    while ($true) {
        $event = $watcher.WaitForNextEvent()
        $drive = $event.DriveName
        Write-Host "[$(Get-Date -Format 'HH:mm:ss')] USB接続: $drive"
        # バッチを呼び出す
        Start-Process -FilePath "cmd.exe" -ArgumentList "/c C:\scripts\usb-action.bat $drive" -Wait -NoNewWindow
    }
} finally {
    $watcher.Stop()
    $watcher.Dispose()
}

注意:実行ポリシーが制限されている環境ではpowershell -ExecutionPolicy Bypass -File script.ps1で起動してください。管理者権限なしでも動作しますが、一部のWMIクエリは管理者権限が必要な場合があります。

方法2:Win32_VolumeChangeEvent の EventType 一覧

EventTypeプロパティはドライブ変化の種類を数値で表します。USBの接続・取り外しには2と3を使います。

EventType値 意味 発生タイミング 用途例
1 構成変更 ドライブの構成が変化したとき パーティション変更の検知
2 ドライブ追加 USB・ネットワークドライブが接続されたとき USB接続検知・自動バックアップ起動
3 ドライブ削除 USBを取り外したとき 取り外しログ記録・セキュリティ通知
4 メディア変更 CD/DVDにメディアを挿入したとき 光学メディアの自動処理
7 空き領域変更 ドライブの空き容量が変化したとき ディスク容量監視

接続・取り外し両方を監視するにはWHERE句を変更します。

接続・取り外し両方を監視するクエリ
$query = "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2 OR EventType = 3"

# イベント受信後の分岐
switch ($event.EventType) {
    2 { Write-Host "接続: $($event.DriveName)";  & "C:\scripts\on-connect.bat"  $event.DriveName }
    3 { Write-Host "取り外し: $($event.DriveName)"; & "C:\scripts\on-disconnect.bat" $event.DriveName }
}

方法2:バッチをランチャーにしてPowerShellから呼び出す

PowerShellでイベントを検知し、実際の処理はバッチファイルに委ねる構成が実用的です。既存のバッチ資産を活かしつつ即時検知の恩恵を受けられます。

usb-launcher.bat:PowerShellを起動するランチャーバッチ
@echo off
set PS_SCRIPT="%~dp0usb-watcher.ps1"

if not exist %PS_SCRIPT% (
    echo エラー: %PS_SCRIPT% が見つかりません
    exit /b 1
)

echo USB監視を開始します...
powershell -ExecutionPolicy Bypass -WindowStyle Hidden -File %PS_SCRIPT%
exit /b 0
usb-action.bat:PowerShellから呼び出されるアクションバッチ
@echo off
setlocal
set DRIVE=%~1

if "%DRIVE%"=="" (
    echo エラー: ドライブレターが指定されていません
    exit /b 1
)

rem ドライブ初期化待ち
ping -n 3 127.0.0.1 >nul
if not exist "%DRIVE%\" (
    echo ドライブ %DRIVE% が使用できません
    exit /b 1
)

echo [%date% %time%] %DRIVE% が接続されました
rem ここにUSB接続時の処理を記述
endlocal
exit /b 0

方法2:USBシリアルナンバーで特定デバイスのみ処理する

ボリュームラベルは簡単に変更できるため、セキュリティや確実性が必要な場面では不向きです。USBデバイスのシリアルナンバー(製造番号)は書き換えが困難で、同一ラベルの別USBを区別できます。

まず接続中のUSBのシリアルナンバーを確認します。

シリアルナンバーの確認コマンド
rem すべてのリムーバブルドライブのシリアルナンバーを一覧表示
wmic logicaldisk where DriveType=2 get Caption,VolumeName,VolumeSerialNumber
usb-action.bat:シリアルナンバーで特定デバイスを識別
@echo off
setlocal
set DRIVE=%~1
set ALLOWED_SERIAL=1A2B3C4D

rem 接続されたドライブのシリアルナンバーを取得
for /f "skip=1 delims=" %%S in (
    'wmic logicaldisk where "Caption='%DRIVE%'" get VolumeSerialNumber'
) do set SERIAL=%%S & goto :check
:check
set SERIAL=%SERIAL: =%

if /i "%SERIAL%"=="%ALLOWED_SERIAL%" (
    echo 許可済みUSB確認: %DRIVE%
    call :do_process
) else (
    echo 未登録USB: %DRIVE% [SN: %SERIAL%] - スキップ
    echo %date% %time%  未登録  %DRIVE%  %SERIAL% >> C:\Logs\usb_unknown.log
)
endlocal
exit /b 0

:do_process
echo 処理を実行します
exit /b 0

複数の許可USBに対応する方法

  • 許可シリアルをテキストファイルに1行1シリアルで保存し、find "%SERIAL%" allowed.txtで照合するのが管理しやすい
  • 複数変数に登録する場合はset ALLOWED_1=SERIAL1と連番で定義し、for /lでループして照合する

実践テンプレート:特定USBが刺さったらドキュメントを自動バックアップ

許可済みUSBが接続されたら、Documentsフォルダを自動バックアップします。日付付きフォルダに保存されるため、世代管理もできます。

auto-backup.bat:Documents自動バックアップ
@echo off
setlocal
set DRIVE=%~1
set ALLOWED_SERIAL=1A2B3C4D
set SRC=%USERPROFILE%\Documents
set LOG=C:\Logs\backup.log

ping -n 4 127.0.0.1 >nul
if not exist "%DRIVE%\" ( echo ドライブ未使用 & exit /b 1 )

rem シリアルナンバー取得・照合
for /f "skip=1 delims=" %%S in (
    'wmic logicaldisk where "Caption='%DRIVE%'" get VolumeSerialNumber'
) do set SN=%%S & goto :sn_done
:sn_done
set SN=%SN: =%

if /i not "%SN%"=="%ALLOWED_SERIAL%" (
    echo 未登録デバイス [%SN%] & exit /b 0
)

rem バックアップ先(日付付きフォルダ)
set DATE_STR=%date:~0,4%%date:~5,2%%date:~8,2%
set DEST="%DRIVE%\Backup\%COMPUTERNAME%_%DATE_STR%"
if not exist %DEST% mkdir %DEST%

echo %date% %time%  開始  %DRIVE% >> %LOG%
xcopy "%SRC%" %DEST% /e /y /q

if %ERRORLEVEL%==0 (
    echo バックアップ完了: %DEST%
    echo %date% %time%  完了 >> %LOG%
) else (
    echo エラー [ERRORLEVEL: %ERRORLEVEL%]
    echo %date% %time%  エラー  %ERRORLEVEL% >> %LOG%
)
endlocal
exit /b 0

実践テンプレート:robocopyによる写真の自動同期バッチ

大量の写真ファイルを差分同期するにはrobocopyが適しています。差分コピー(変更があったファイルのみコピー)と詳細なログ出力に優れています。

photo-sync.bat:robocopyによる写真自動同期
@echo off
setlocal
set DRIVE=%~1
set SRC="%DRIVE%\DCIM"
set DEST="%USERPROFILE%\Pictures\AutoSync"
set LOG_DIR=C:\Logs\PhotoSync
set DATE_STR=%date:~0,4%%date:~5,2%%date:~8,2%
set TIME_STR=%time:~0,2%%time:~3,2%
set LOG="%LOG_DIR%\sync_%DATE_STR%_%TIME_STR%.log"

if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
if not exist %SRC% ( echo DCIMフォルダなし & exit /b 1 )

echo 写真同期開始: %SRC% → %DEST%

rem /E=サブフォルダ含む /XO=既存の新しいファイルスキップ /R:3=再試行3回
robocopy %SRC% %DEST% *.jpg *.jpeg *.png *.mov *.mp4 *.heic /e /xo /r:3 /w:5 /log:%LOG% /tee /np

rem robocopyの終了コードは0〜7が正常範囲(0=変更なし、1=新規コピーあり)
if %ERRORLEVEL% leq 7 (
    echo 同期完了 [RC=%ERRORLEVEL%]
) else (
    echo 同期エラー [RC=%ERRORLEVEL%] ログ: %LOG%
)
endlocal
exit /b 0

ポイント:robocopyの終了コードは0〜7が正常範囲です。通常のif %ERRORLEVEL% equ 0では正常終了を誤検知するため、if %ERRORLEVEL% leq 7で正常判定してください。8以上がエラーです。

実践テンプレート:USB接続ログをCSVに記録するバッチ

誰がいつどのUSBを接続したかを記録することはセキュリティ管理と運用証跡として重要です。接続情報をCSV形式で蓄積します。

usb-csv-log.bat:USB接続をCSVに記録
@echo off
setlocal enabledelayedexpansion
set DRIVE=%~1
set EVENT_TYPE=%~2
set CSV=C:\Logs\usb_history.csv

rem CSVヘッダーが存在しない場合は作成
if not exist "%CSV%" (
    if not exist "C:\Logs" mkdir "C:\Logs"
    echo 日時,コンピュータ名,ユーザー名,ドライブ,ボリュームラベル,シリアルナンバー,イベント > "%CSV%"
)

rem ドライブ情報を取得
for /f "skip=1 tokens=2,3 delims=," %%A in (
    'wmic logicaldisk where "Caption='%DRIVE%'" get VolumeName,VolumeSerialNumber /format:csv'
) do (
    if not "%%A"=="" (
        set VOL_LABEL=%%A
        set SERIAL=%%B
        goto :got_info
    )
)
:got_info

set DT=%date:~0,4%/%date:~5,2%/%date:~8,2% %time:~0,8%
echo "%DT%","%COMPUTERNAME%","%USERNAME%","%DRIVE%","%VOL_LABEL%","%SERIAL%","%EVENT_TYPE%" >> "%CSV%"
echo ログ記録完了: %DT%  %DRIVE%
endlocal
exit /b 0

PowerShellから接続・取り外し両方をCSVに記録する場合はイベントタイプも引数で渡します。

PowerShellからCSVログバッチを呼び出す
$event = $watcher.WaitForNextEvent()
$drive = $event.DriveName
$etype = if ($event.EventType -eq 2) { "接続" } else { "取り外し" }
Start-Process -FilePath "cmd.exe" -ArgumentList "/c C:\scripts\usb-csv-log.bat $drive $etype" -Wait -NoNewWindow

タスクスケジューラでログオン時に監視バッチを自動起動する

USB監視バッチをWindowsログオン時に自動起動するにはタスクスケジューラに登録します。

タスクスケジューラへの登録(管理者権限で実行)
schtasks /create ^
  /tn "USB監視" ^
  /tr "powershell -ExecutionPolicy Bypass -WindowStyle Hidden -File C:\scripts\usb-watcher.ps1" ^
  /sc onlogon ^
  /ru "%USERNAME%" ^
  /f

rem 登録確認
schtasks /query /tn "USB監視"

rem 手動起動(テスト用)
schtasks /run /tn "USB監視"

タスクスケジューラ設定のポイント

  • 開始(オプション):スクリプトファイルのフォルダパス(C:\scripts)を必ず設定する。空のままだとSystem32がカレントになりパスが狂う
  • 条件:「AC電源接続時のみ」のチェックを外す(ラップトップでも確実に動かすため)
  • 設定:「タスクが既に実行中の場合」→「新しいインスタンスを開始しない」を選択し多重起動を防ぐ
  • トリガー:「ログオン時」を選択し、特定ユーザーに限定するとセキュリティが高まる

安全設計:ドライブ検証・二重チェック・待機処理

USB検知バッチを本番運用するうえで必要な安全設計ポイントをまとめます。

1. ドライブが使用可能になるまで待機する

WMIイベントが発火してもドライブのファイルシステム初期化が完了するまでに短時間かかります。ループでドライブの存在を確認してから処理します。

ドライブが使用可能になるまで待機するパターン
@echo off
setlocal
set DRIVE=%~1
set MAX_WAIT=30
set CNT=0

:wait
if exist "%DRIVE%\" goto :ready
set /a CNT+=1
if %CNT% geq %MAX_WAIT% ( echo タイムアウト & exit /b 1 )
ping -n 2 127.0.0.1 >nul
goto :wait

:ready
echo ドライブ %DRIVE% 使用可能(%CNT%秒待機)
rem ここからメイン処理
endlocal
exit /b 0

2. ロックファイルによる二重実行防止

ポーリング間隔が短く、前のコピー処理が終わらないうちに次のループが回ると二重実行が起きます。

ロックファイルによる二重実行防止
@echo off
setlocal
set LOCK="%TEMP%\usb_action.lock"

if exist %LOCK% ( echo 前の処理が実行中 - スキップ & exit /b 0 )
echo %date% %time% > %LOCK%

call :main_process
set RES=%ERRORLEVEL%

del /f /q %LOCK% 2>nul
endlocal
exit /b %RES%

:main_process
echo メイン処理実行中...
exit /b 0

3. コピー前の空き容量チェック

コピー先の空き容量が足りないままコピーを実行すると途中で失敗します。wmicで空き容量を取得して最低限の容量を確認します。

空き容量チェック(GB単位)
@echo off
setlocal
set DEST_DRIVE=C:
set MIN_FREE_GB=5

for /f "skip=1 delims=" %%F in (
    'wmic logicaldisk where "Caption='%DEST_DRIVE%'" get FreeSpace'
) do set FREE=%%F & goto :got
:got
set FREE=%FREE: =%
set /a FREE_GB=%FREE:~0,-9%

if %FREE_GB% lss %MIN_FREE_GB% (
    echo エラー: 空き容量不足 [%FREE_GB%GB / 最低%MIN_FREE_GB%GB必要]
    exit /b 1
)
echo 空き容量OK: %FREE_GB%GB
endlocal
exit /b 0

トラブルシューティング:よくあるエラーと対処法

症状・エラー 原因 対処法
wmicが出力を返さない USBが未接続またはDriveType指定違い wmic logicaldisk get Caption,DriveTypeで全ドライブのタイプを確認する
for /fでwmic出力が取得できない wmicがUTF-16 BOM付きで出力している /format:csvを使うかPowerShellのGet-CimInstanceに切り替える
ボリュームラベルが空欄になる USBにラベルが設定されていない if "%LABEL%"==""でラベルなしケースの処理を追加する
接続直後にドライブが見つからない ドライブ初期化が完了していない ping -n 4 127.0.0.1で3秒待機してからアクセスする
ExecutionPolicyエラー PowerShellのスクリプト実行ポリシーが制限 powershell -ExecutionPolicy Bypass -File script.ps1で起動する
WMIイベントが発火しない WMIサービスが停止またはクエリ構文エラー net start winmgmtでWMIサービスを確認し、クエリをPowerShellコンソールで直接テストする
robocopy終了コード8以上 権限・容量・パスの問題によるコピーエラー ログファイルで失敗ファイルを特定する。/R:0 /W:0でエラーをスキップして継続する運用も可
タスクスケジューラで動かない カレントディレクトリがSystem32になっている タスクの「開始(オプション)」にスクリプトのフォルダパスを設定する
同じUSBを何度も処理してしまう 取り外し・再接続のたびにイベントが発火 ロックファイルまたは処理済みシリアルナンバーをファイルに記録してスキップする
「wmicは認識されていません」 Windows 11 22H2以降でwmicが非推奨・無効化 PowerShellのGet-CimInstance Win32_LogicalDisk -Filter "DriveType=2"に置き換える

注意:Windows 11 22H2以降でwmicコマンドは非推奨(deprecated)扱いです。将来的に削除される可能性があります。新規実装ではPowerShellのGet-CimInstance Win32_LogicalDisk -Filter "DriveType=2" | Select-Object DeviceID,VolumeName,VolumeSerialNumberを使うことを推奨します。

まとめ

バッチファイルとPowerShellを使ったUSBデバイス検知の方法を2種類解説しました。

ポーリング方式(wmic)はバッチファイル単体で完結し、学習コストが低いのが特徴です。5〜10秒間隔の監視で十分な用途、たとえば写真の自動取り込みやバックアップ開始の合図としては十分実用的です。

WMIイベント方式(PowerShell)はUSB接続の瞬間を即時検知でき、CPU負荷もほぼゼロです。セキュリティ管理や業務自動化のような本番運用に適しています。PowerShellを起動媒介にしてバッチファイルを呼び出す構成にすれば、既存の処理ロジックを活かしたまま即時検知の恩恵を受けられます。

用途 推奨方式 使うテンプレート
USB検知の学習・試作 ポーリング(wmic) usb-monitor.bat / usb-diff.bat
写真・ファイルの自動同期 どちらでも可 photo-sync.bat(robocopy)
ドキュメントの自動バックアップ WMIイベント推奨 auto-backup.bat + usb-watcher.ps1
USB接続ログの記録 WMIイベント推奨 usb-csv-log.bat
特定デバイスのみ許可する管理 WMIイベント推奨 シリアルナンバー識別テンプレート
ログオン時の自動起動 タスクスケジューラ schtasks登録コマンド

いずれの方式でも、接続後の待機処理・ドライブ存在確認・ロックファイルによる二重実行防止の3点を組み込むことで、安定して動作するバッチになります。まずポーリング方式で動作を確認し、本番投入前にWMIイベント方式へ移行するステップが最もスムーズです。