社内の10台のPCにソフトウェア更新を配布したい、全サーバーのサービス状態を確認したい、特定のレジストリ値を一括変更したい——こうした作業を1台ずつRDPで接続して実行するのは時間がかかり、漏れも発生します。
バッチファイルとWindowsが標準で持つリモート実行の仕組みを組み合わせると、ホストリストを用意するだけで数十台に同じコマンドを一括送信できます。方法は1つではなく、環境やセキュリティ要件に応じて使い分けが必要です。
この記事では、PsExec・WinRM(PowerShell Remoting)・WMI・OpenSSH・schtasks方式の5つを比較し、それぞれのセットアップ・バッチ実装・エラー処理・ログ記録まで体系的に解説します。PsExecの詳細はバッチファイルで複数PCに一括コマンドを送信する方法(PsExec活用)で深く解説しているため、合わせて参照してください。
5つのリモート実行方式の比較と用途別の使い分け基準、ホストリストからfor /fでループして一括実行するパターン、PsExecで複数PCにコマンドを一括送信する基本と応用、WinRM(winrm quickconfig)のセットアップとバッチからの呼び出し方、WMI(wmic /node)でリモートPCの情報を取得・コマンドを実行する方法、OpenSSH(Windows標準機能)でSSH越しにコマンドを送る方法、エラー時の通知・ログ記録・セキュリティ対策の実装方法
5つのリモート実行方式の比較
まず各方式の特徴を比較して、自環境に合った方法を選びましょう。
| 方式 | 必要なセットアップ | 認証 | 向いている用途 | 注意点 |
|---|---|---|---|---|
| PsExec | PsExec.exeを配置するだけ | Windowsユーザー/パスワード | 手軽な一括実行・ファイルコピー+実行 | セキュリティソフトが誤検知することがある |
| WinRM (PowerShell Remoting) |
winrm quickconfig ファイアウォール設定 |
Windowsユーザー/パスワード | PowerShellコマンドの一括実行・収集 | 初期設定が必要。ドメイン環境で使いやすい |
| WMI (wmic /node) |
WMI有効化(多くはデフォルト) | Windowsユーザー/パスワード | リモートPCの情報収集・プロセス実行 | 戻り値が取りにくい・文字コード注意 |
| OpenSSH | サーバー側にOpenSSH Serverをインストール | SSH鍵またはパスワード | Linux混在環境・スクリプト実行 | Windows 10 1809 / Server 2019以降が必要 |
| schtasks /s | 対象PCへのファイアウォール許可 | Windowsユーザー/パスワード | タスク登録してバッチをリモート起動 | スケジューラ経由のため即時実行ではない |
・最速で始めたい→ PsExec(配置だけで動く)
・ドメイン環境・PowerShell多用→ WinRM
・情報収集メイン→ WMI(wmic /node)
・Linux混在・SSH標準化→ OpenSSH
・管理者権限で非同期実行→ schtasks /s
共通基盤:ホストリストから一括実行するパターン
どの方式を使う場合も、対象PCのリストを外部ファイルに持ち、for /f でループして1台ずつコマンドを送る基本構造は共通です。
:: 先頭が :: の行はコメント(スキップ) :: ホスト名またはIPアドレスを1行に1つ記載 PC-CLIENT-01 PC-CLIENT-02 192.168.1.103 FILESERVER-01 :: PC-TEST-01 ← コメントアウトで一時除外
@echo off
setlocal enabledelayedexpansion
set "BASE=%~dp0"
set "HOSTS=%BASE%hosts.txt"
set "LOGDIR=%BASE%logs"
set "LOG=%LOGDIR%
emote_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
if not exist "%HOSTS%" (
echo [ERROR] ホストリストが見つかりません: %HOSTS%
exit /b 1
)
set /a OK=0
set /a FAIL=0
set /a SKIP=0
echo ============================================ >> "%LOG%"
echo 開始: %DATE% %TIME% >> "%LOG%"
echo ============================================ >> "%LOG%"
for /f "usebackq eol=: delims=" %%H in ("%HOSTS%") do (
if not "%%H"=="" (
echo [TARGET] %%H
echo [TARGET] %%H >> "%LOG%"
:: ── ここに各方式のリモート実行コマンドを入れる ──
call :remote_exec "%%H"
set /a RC=!ERRORLEVEL!
:: ──────────────────────────────────────────────
if !RC! EQU 0 (
set /a OK+=1
echo [OK] %%H >> "%LOG%"
) else (
set /a FAIL+=1
echo [FAIL] %%H ERRORLEVEL=!RC! >> "%LOG%"
echo [FAIL] %%H - エラーコード: !RC!
)
)
)
echo ============================================ >> "%LOG%"
echo 完了: OK=%OK% FAIL=%FAIL% SKIP=%SKIP% >> "%LOG%"
echo ============================================ >> "%LOG%"
echo.
echo 実行結果: 成功 %OK% / 失敗 %FAIL% / スキップ %SKIP%
if !FAIL! GTR 0 exit /b 1
exit /b 0
:: ── リモート実行サブルーチン(方式によって中身を変える) ──
:remote_exec
setlocal
set "HOST=%~1"
:: ここに実行コマンドを書く(後続のセクションを参照)
echo 実行中: !HOST!
endlocal
exit /b 0
for /f "eol=: delims=" の eol=: で、:: で始まる行(コメント)を自動的にスキップします。一時的に除外したいホストはコメントアウトするだけでOKです。方式1:PsExec(最もシンプルな一括実行)
PsExec は Microsoft Sysinternals が提供するツールで、インストール不要でリモートPCのコマンドを実行できます。バッチファイルで複数PCに一括コマンドを送信する方法(PsExec活用)でコマンドオプションや実践パターンを詳しく解説しているため、ここでは基本構造と一括実行の骨格のみ示します。
事前準備
| 確認項目 | 設定方法 |
|---|---|
| PsExec.exeの入手 | https://learn.microsoft.com/ja-jp/sysinternals/downloads/psexec からダウンロード |
| ターゲットPCのファイアウォール | 「ファイルとプリンターの共有」を有効化(ポート445) |
| 管理者共有(ADMIN$) | デフォルトで有効。無効化している場合は再有効化が必要 |
| 実行ユーザー | 対象PCのローカル管理者または同一ドメインの管理者アカウント |
@echo off
setlocal enabledelayedexpansion
set "BASE=%~dp0"
set "PSEXEC=%BASE%PsExec.exe"
set "HOSTS=%BASE%hosts.txt"
set "LOGDIR=%BASE%logs"
set "LOG=%LOGDIR%\psexec_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
set "REMOTE_USER=domaindmin"
:: パスワードは環境変数や資格情報マネージャーから取得することを推奨
set /p REMOTE_PASS=パスワードを入力してください:
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set /a OK=0
set /a FAIL=0
for /f "usebackq eol=: delims=" %%H in ("%HOSTS%") do (
if not "%%H"=="" (
echo [TARGET] %%H
echo [%DATE% %TIME%] [TARGET] %%H >> "%LOG%"
"%PSEXEC%" \%%H -u "%REMOTE_USER%" -p "%REMOTE_PASS%" ^
-h -accepteula ^
cmd /c "ipconfig /all" ^
>> "%LOG%" 2>&1
set /a RC=!ERRORLEVEL!
if !RC! EQU 0 (
set /a OK+=1
echo [OK] %%H >> "%LOG%"
) else (
set /a FAIL+=1
echo [FAIL] %%H ERR=!RC! >> "%LOG%"
echo [FAIL] %%H - エラーコード: !RC!
)
)
)
echo 完了: 成功 %OK% / 失敗 %FAIL%
バッチ内に
set "PASS=password" のようにパスワードを直書きすることはセキュリティリスクがあります。代替案として、①set /p でその都度入力、②Windowsの資格情報マネージャーを利用(PsExec は -n オプションで資格情報マネージャー参照)、③実行アカウントをタスクスケジューラで設定してパスワード不要にする、の3つを検討してください。複数PCにファイルをコピーして実行する
@echo off
setlocal enabledelayedexpansion
set "PSEXEC=PsExec.exe"
set "SCRIPT=C: ools\deploy.bat"
set "REMOTE_USER=domaindmin"
set /p REMOTE_PASS=パスワード:
for /f "usebackq eol=: delims=" %%H in ("hosts.txt") do (
if not "%%H"=="" (
echo [%%H] ファイルコピー中...
:: ファイルをリモートPCにコピー
copy /y "%SCRIPT%" "\%%Hdmin$ emp\deploy.bat" > nul 2>&1
if !ERRORLEVEL! NEQ 0 (
echo [FAIL] %%H - ファイルコピー失敗
) else (
echo [%%H] コマンド実行中...
"%PSEXEC%" \%%H -u "%REMOTE_USER%" -p "%REMOTE_PASS%" -h -accepteula ^
cmd /c "C:\Windows\Temp\deploy.bat"
echo [%%H] 完了: ERRORLEVEL=!ERRORLEVEL!
)
)
)
方式2:WinRM(PowerShell Remoting)
WinRM(Windows Remote Management)はWindowsに標準搭載されたリモート管理プロトコルです。PowerShell Remoting の基盤となっており、コマンド1つでセットアップできます。ドメイン環境では特に相性がよく、Kerberos認証でパスワードを直書きせずに実行できます。
WinRMのセットアップ(対象PC側)
# 対象PC側で実行(管理者権限のPowerShellで) Enable-PSRemoting -Force # ファイアウォールルール確認 Get-NetFirewallRule -DisplayName "*Windows Remote Management*" | Select Name, Enabled # 特定のホストからの接続のみ許可(セキュリティ強化) Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.1.*" -Force # 確認 winrm enumerate winrm/config/listener
:: 接続テスト(コマンドプロンプトから) winrm id -r:http://TARGET-PC:5985 :: PowerShellからテスト powershell -Command "Test-WSMan -ComputerName TARGET-PC"
バッチからPowerShell Remotingを呼び出す
@echo off
setlocal enabledelayedexpansion
set "HOSTS=%~dp0hosts.txt"
set "LOGDIR=%~dp0logs"
set "LOG=%LOGDIR%\winrm_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
set "REMOTE_USER=domaindmin"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set /a OK=0
set /a FAIL=0
for /f "usebackq eol=: delims=" %%H in ("%HOSTS%") do (
if not "%%H"=="" (
echo [TARGET] %%H
echo [%DATE% %TIME%] [START] %%H >> "%LOG%"
:: PowerShell Remotingで実行(ドメイン環境はパスワード不要)
powershell -NoProfile -Command ^
"Invoke-Command -ComputerName '%%H' -ScriptBlock { ^
$hostname = $env:COMPUTERNAME; ^
$os = (Get-CimInstance Win32_OperatingSystem).Caption; ^
"$hostname: $os" ^
}" >> "%LOG%" 2>&1
set /a RC=!ERRORLEVEL!
if !RC! EQU 0 (
set /a OK+=1
echo [OK] %%H >> "%LOG%"
) else (
set /a FAIL+=1
echo [FAIL] %%H ERR=!RC! >> "%LOG%"
echo [FAIL] %%H
)
)
)
echo 完了: 成功 %OK% / 失敗 %FAIL%
echo 完了: 成功 %OK% / 失敗 %FAIL% >> "%LOG%"
if !FAIL! GTR 0 exit /b 1
exit /b 0
@echo off
setlocal enabledelayedexpansion
set "REMOTE_USER=localadmin"
set /p REMOTE_PASS=パスワード:
for /f "usebackq eol=: delims=" %%H in ("hosts.txt") do (
if not "%%H"=="" (
echo [%%H] 実行中...
:: クレデンシャルを指定してInvoke-Command
powershell -NoProfile -Command ^
"$pw = ConvertTo-SecureString '%REMOTE_PASS%' -AsPlainText -Force; ^
$cred = New-Object PSCredential('%REMOTE_USER%', $pw); ^
Invoke-Command -ComputerName '%%H' -Credential $cred -ScriptBlock { ^
Get-Service -Name 'Spooler' ^
}" 2>&1
if !ERRORLEVEL! EQU 0 (echo [OK] %%H) else (echo [FAIL] %%H)
)
)
Copy-Item -ToSession と Invoke-Command を組み合わせると、PowerShell Remotingセッション経由でスクリプトファイルをコピーして実行できます。共有フォルダなしでファイル転送できるため、ネットワーク構成がシンプルになります。方式3:WMI(wmic /node)でリモート情報収集・実行
WMI(Windows Management Instrumentation)はWindowsの管理情報にアクセスする標準インターフェースです。wmic /node でリモートPCに接続し、情報取得やプロセス起動ができます。セットアップ不要(WMIはデフォルトで有効)で使えるのが利点ですが、Windows 11 / Server 2025 以降では非推奨となり、PowerShell の Get-CimInstance が推奨されます。
@echo off
setlocal enabledelayedexpansion
set "LOGDIR=%~dp0logs"
set "LOG=%LOGDIR%\wmi_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.csv"
set "REMOTE_USER=domaindmin"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
:: CSVヘッダー
echo HostName,OSCaption,TotalMemoryGB,FreeMemoryGB >> "%LOG%"
for /f "usebackq eol=: delims=" %%H in ("hosts.txt") do (
if not "%%H"=="" (
echo [INFO] %%H 情報収集中...
:: OS情報取得
for /f "skip=1 tokens=*" %%O in (
'wmic /node:%%H /user:"%REMOTE_USER%" os get Caption /format:csv 2^>nul'
) do (
if not "%%O"=="" set "OS_CAP=%%O"
)
:: メモリ取得(MB → GB 変換)
for /f "skip=1 tokens=*" %%M in (
'wmic /node:%%H /user:"%REMOTE_USER%" computersystem get TotalPhysicalMemory /format:csv 2^>nul'
) do (
if not "%%M"=="" (
set /a TOTAL_GB=%%M / 1073741824
)
)
echo %%H,!OS_CAP!,!TOTAL_GB! >> "%LOG%"
)
)
echo 完了: %LOG% に保存しました。
@echo off
setlocal enabledelayedexpansion
set "REMOTE_USER=domaindmin"
set /p REMOTE_PASS=パスワード:
for /f "usebackq eol=: delims=" %%H in ("hosts.txt") do (
if not "%%H"=="" (
echo [%%H] プロセス起動...
:: wmic process call create でリモートプロセス起動
wmic /node:%%H /user:"%REMOTE_USER%" /password:"%REMOTE_PASS%" ^
process call create "cmd /c C:\tools\update.bat > C:\logs\update.log 2>&1"
if !ERRORLEVEL! EQU 0 (
echo [OK] %%H - プロセス起動成功
) else (
echo [FAIL] %%H - プロセス起動失敗
)
)
)
wmic process call create はプロセスの起動成功を返すだけで、起動したプロセスの終了コードは取得できません。非同期実行として扱ってください。また、wmic の出力は UTF-16 LE のため、for /f で取得した値が文字化けする場合があります。その場合は powershell -Command "Get-CimInstance ..." への置き換えを検討してください。方式4:OpenSSH(Windows標準のSSH機能)
Windows 10 バージョン 1809 / Windows Server 2019 以降は、OpenSSH Server が標準機能として搭載されています。Linux・Mac・他のWindowsどこからでもSSH経由でコマンドを実行できるため、異種OS混在環境や将来的な互換性を重視する場合に最適です。
OpenSSH Serverのセットアップ(対象PC側)
# インストール(管理者PowerShell) Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 # サービス起動 + 自動起動設定 Start-Service sshd Set-Service -Name sshd -StartupType Automatic # ファイアウォール確認(自動で設定されるが念のため確認) Get-NetFirewallRule -Name *ssh* # SSH鍵認証を設定する場合(推奨) # authorized_keysファイルを作成 # C:\ProgramData\sshdministrators_authorized_keys に管理者用公開鍵を追加
バッチからSSH一括実行
@echo off
setlocal enabledelayedexpansion
set "HOSTS=%~dp0hosts.txt"
set "SSH_KEY=%USERPROFILE%\.ssh\id_rsa"
set "REMOTE_USER=admin"
set "LOGDIR=%~dp0logs"
set "LOG=%LOGDIR%\ssh_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set /a OK=0
set /a FAIL=0
for /f "usebackq eol=: delims=" %%H in ("%HOSTS%") do (
if not "%%H"=="" (
echo [TARGET] %%H
echo [%DATE% %TIME%] [TARGET] %%H >> "%LOG%"
:: SSH鍵認証でリモートコマンドを実行
ssh -i "%SSH_KEY%" ^
-o StrictHostKeyChecking=no ^
-o ConnectTimeout=10 ^
-o BatchMode=yes ^
%REMOTE_USER%@%%H ^
"ipconfig /all && echo EXIT_CODE=0" >> "%LOG%" 2>&1
set /a RC=!ERRORLEVEL!
if !RC! EQU 0 (
set /a OK+=1
echo [OK] %%H >> "%LOG%"
echo [OK] %%H
) else (
set /a FAIL+=1
echo [FAIL] %%H ERR=!RC! >> "%LOG%"
echo [FAIL] %%H
)
)
)
echo 完了: 成功 %OK% / 失敗 %FAIL%
echo 完了: 成功 %OK% / 失敗 %FAIL% >> "%LOG%"
if !FAIL! GTR 0 exit /b 1
exit /b 0
@echo off
setlocal enabledelayedexpansion
set "SSH_KEY=%USERPROFILE%\.ssh\id_rsa"
set "REMOTE_USER=admin"
set "LOCAL_SCRIPT=C: ools\deploy.sh"
for /f "usebackq eol=: delims=" %%H in ("hosts.txt") do (
if not "%%H"=="" (
echo [%%H] スクリプトをコピー中...
:: scpでスクリプトをコピー
scp -i "%SSH_KEY%" -o BatchMode=yes "%LOCAL_SCRIPT%" ^
%REMOTE_USER%@%%H:/tmp/deploy.sh
if !ERRORLEVEL! EQU 0 (
echo [%%H] 実行中...
:: コピー後に実行(PowerShellスクリプトを実行)
ssh -i "%SSH_KEY%" -o BatchMode=yes ^
%REMOTE_USER%@%%H "powershell -ExecutionPolicy Bypass -File C:\tools\deploy.ps1"
echo [%%H] 結果: !ERRORLEVEL!
) else (
echo [FAIL] %%H - コピー失敗
)
)
)
管理者用の公開鍵は
C:\ProgramData\ssh\administrators_authorized_keys に配置します(通常ユーザーは %USERPROFILE%\.ssh\authorized_keys)。アクセス許可は特定のアカウントのみに制限し、グループやEveryoneには与えないでください。詳細は Microsoft の公式ドキュメント「OpenSSH key management」を参照してください。方式5:schtasks /s でリモートにタスクを登録して実行
schtasks コマンドの /s オプションで、リモートPCのタスクスケジューラにタスクを登録・即時実行できます。schtasksコマンドでタスクスケジューラを完全制御する完全ガイドでschtasksの詳細な使い方を解説しています。この方式はバッチファイルやスクリプトをリモートPCで実行させたいが、対象PCに既にファイルが存在する場合に特に有効です。
@echo off
setlocal enabledelayedexpansion
set "REMOTE_USER=domaindmin"
set /p REMOTE_PASS=パスワード:
set "TASK_NAME=RemoteDeploy_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"
set "REMOTE_BAT=C: ools\deploy.bat"
set "LOGDIR=%~dp0logs"
set "LOG=%LOGDIR%\schtask_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
for /f "usebackq eol=: delims=" %%H in ("hosts.txt") do (
if not "%%H"=="" (
echo [%%H] タスク登録中...
:: リモートPCにタスクを登録
schtasks /create ^
/s %%H ^
/u "%REMOTE_USER%" /p "%REMOTE_PASS%" ^
/tn "%TASK_NAME%" ^
/tr ""%REMOTE_BAT%"" ^
/sc once /st 00:00 ^
/ru SYSTEM ^
/f > nul 2>&1
if !ERRORLEVEL! NEQ 0 (
echo [FAIL] %%H - タスク登録失敗
) else (
:: 即時実行
schtasks /run /s %%H /u "%REMOTE_USER%" /p "%REMOTE_PASS%" /tn "%TASK_NAME%" > nul 2>&1
echo [OK] %%H - タスク起動 >> "%LOG%"
echo [OK] %%H - タスク起動
:: 後で削除(任意)
:: schtasks /delete /s %%H /u "%REMOTE_USER%" /p "%REMOTE_PASS%" /tn "%TASK_NAME%" /f
)
)
)
echo 完了。各PCでタスクが実行されています。
schtasks /s 方式では、リモートPC上で
SYSTEM 権限(または任意のサービスアカウント)でバッチを実行できます。ネットワーク越しの共有フォルダへのアクセスはSYSTEM権限では制限される場合があるため、管理者権限で自動実行するバッチファイルの作り方も合わせて確認してください。実践:全台を並列で高速実行する
対象が10台以上になると、順次実行では時間がかかります。バッチファイルで並列処理を実行する方法のパターンを応用し、複数台に同時にコマンドを送ることで大幅な時間短縮ができます。
@echo off
setlocal enabledelayedexpansion
set "BASE=%~dp0"
set "HOSTS=%BASE%hosts.txt"
set "LOCKDIR=%TEMP%
locks_%RANDOM%"
set "LOGDIR=%BASE%logs"
set "LOG=%LOGDIR%\parallel_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
mkdir "%LOCKDIR%"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set /a TOTAL=0
:: ── 全ホストを並列起動 ────────────────────────────────
for /f "usebackq eol=: delims=" %%H in ("%HOSTS%") do (
if not "%%H"=="" (
set /a TOTAL+=1
:: ロックファイルを事前に作成
copy nul "%LOCKDIR%\%%H.lock" > nul
:: バックグラウンドでPsExecを実行(完了後にロックファイルを削除)
start /b cmd /c "psexec \%%H -accepteula -h ipconfig /all >> "%LOG%" 2>&1 && del "%LOCKDIR%\%%H.lock" 2>nul || del "%LOCKDIR%\%%H.lock" 2>nul"
echo [LAUNCH] %%H
)
)
echo %TOTAL% 台に同時送信しました。完了を待機中...
:: ── 全ロックファイルが消えるまで待機(最大 120 秒)────
set /a WAIT=0
:wait_loop
timeout /t 3 /nobreak > nul
set /a WAIT+=3
set "REMAIN="
for %%F in ("%LOCKDIR%\*.lock") do set "REMAIN=1"
if defined REMAIN (
if !WAIT! LSS 120 goto :wait_loop
echo [TIMEOUT] 一部のホストが時間内に完了しませんでした。
)
echo 全処理完了(待機時間: %WAIT%秒)
rmdir /s /q "%LOCKDIR%" 2>nul
echo 全処理完了 >> "%LOG%"
エラー処理・ログ記録・通知の実装
大量のPCに送信すると一部で失敗が出るのは避けられません。失敗したホストをログに記録し、リトライリストを生成する仕組みを作っておくと運用が楽になります。バッチファイルでログを出力する方法完全ガイドのログ出力パターンとバッチファイルでエラー通知メールを自動送信する完全ガイドの通知を組み合わせた完成版を示します。
@echo off
setlocal enabledelayedexpansion
set "BASE=%~dp0"
set "HOSTS=%BASE%hosts.txt"
set "FAIL_LIST=%BASE%hosts_failed_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.txt"
set "LOGDIR=%BASE%logs"
set "LOG=%LOGDIR%
emote_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
if exist "%FAIL_LIST%" del "%FAIL_LIST%"
set /a OK=0
set /a FAIL=0
set /a TOTAL=0
echo ============================================ >> "%LOG%"
echo 開始: %DATE% %TIME% >> "%LOG%"
echo ============================================ >> "%LOG%"
for /f "usebackq eol=: delims=" %%H in ("%HOSTS%") do (
if not "%%H"=="" (
set /a TOTAL+=1
:: 接続前にpingで生死確認(タイムアウトを短くして高速化)
ping -n 1 -w 1000 %%H > nul 2>&1
if !ERRORLEVEL! NEQ 0 (
echo [SKIP] %%H - pingタイムアウト(オフラインの可能性)
echo [SKIP] %%H - ping timeout >> "%LOG%"
echo %%H >> "%FAIL_LIST%"
set /a FAIL+=1
) else (
echo [TARGET] %%H
:: ── メインコマンドを実行 ──
psexec \%%H -accepteula -h cmd /c "ipconfig /all" >> "%LOG%" 2>&1
set /a RC=!ERRORLEVEL!
if !RC! EQU 0 (
set /a OK+=1
echo [OK] %%H >> "%LOG%"
echo [OK] %%H
) else (
set /a FAIL+=1
echo [FAIL] %%H ERR=!RC! >> "%LOG%"
echo [FAIL] %%H - エラーコード: !RC!
echo %%H >> "%FAIL_LIST%"
)
)
)
)
echo ============================================ >> "%LOG%"
echo 完了: 全%TOTAL% OK=%OK% FAIL=%FAIL% >> "%LOG%"
echo ============================================ >> "%LOG%"
echo.
echo ────────────────────────────────────────
echo 実行結果: 全 %TOTAL% 台 / 成功 %OK% / 失敗 %FAIL%
if !FAIL! GTR 0 (
echo 失敗リスト: %FAIL_LIST%
echo ヒント: 失敗リストを hosts.txt として再実行できます
)
echo ログ: %LOG%
echo ────────────────────────────────────────
:: 失敗があればメール通知(PowerShell Send-MailMessage)
if !FAIL! GTR 0 (
powershell -NoProfile -Command ^
"Send-MailMessage -From 'batch@example.com' -To 'admin@example.com' ^
-Subject '[ALERT] リモート実行で %FAIL% 台が失敗 (%DATE%)' ^
-Body (Get-Content '%FAIL_LIST%' -Raw) ^
-SmtpServer 'smtp.example.com'"
echo [通知] 失敗リストをメール送信しました。
)
if !FAIL! GTR 0 exit /b 1
exit /b 0
上のスクリプトが生成する
hosts_failed_YYYYMMDD.txt を hosts.txt にリネームして同じスクリプトを再実行するだけで、失敗したホストだけをリトライできます。複数バッチファイルを一括管理・実行するマスタースクリプト完全ガイドの再開機能と組み合わせると、さらに洗練されたリトライ管理が実現できます。セキュリティ上の注意点と対策
リモート実行は便利な反面、適切な制御がなければセキュリティリスクになります。運用前に以下の点を確認してください。
| リスク | 対策 |
|---|---|
| パスワードのコード直書き | 資格情報マネージャー利用、SSH鍵認証、タスクスケジューラのサービスアカウント実行 |
| 不要なポートの開放 | 実行方式に必要なポートのみ開放(PsExec:445、WinRM:5985/5986、SSH:22) |
| ADMIN$共有の悪用 | リモート実行に専用の限定権限アカウントを作成し、管理者権限を最小化 |
| コマンド実行ログの欠如 | 実行コマンドと対象PC・実行時刻を必ずログに記録 |
| ターゲット以外のPCへの誤送 | hosts.txtをdry-runモードで確認してから本番実行(echo のみで確認) |
本番実行前に
--dry-run 的な確認ステップを入れることを強く推奨します。例えば、実際のコマンドを送る前に echo [DRY RUN] %%H にコマンドを送信します だけを表示するモードを用意し、対象ホストの一覧を目視確認してから本番実行してください。誤ったホストに変更系コマンドを送ると取り消しが困難です。よくある質問(FAQ)
TrustedHosts に対象PCを追加する必要があります。OpenSSHはSSH鍵認証を使えばパスワード不要で安全に使えるため、ワークグループ環境でも特におすすめです。psexec \HOST cmd /c "ipconfig" >> local_log.txt 2>&1 の形で問題ありません。ただし、wmicはCSV形式でのみ出力取得が安定しています。また、ssh は -o BatchMode=yes を付けると対話入力を無効化してログに向けやすくなります。まとめ
| 方式 | 主な用途 | 前提条件 | 特徴 |
|---|---|---|---|
| PsExec | 手軽な一括実行・ファイルコピー | PsExec.exe配置・ADMIN$有効 | 設定最小・セキュリティソフト誤検知に注意 |
| WinRM | PowerShellコマンドの一括実行 | Enable-PSRemoting + FW設定 | ドメイン環境に最適・Kerberos認証対応 |
| WMI | 情報収集・プロセス起動 | WMI有効(デフォルト) | 戻り値が非同期・Win11以降は非推奨 |
| OpenSSH | SSH越しのコマンド実行・ファイル転送 | OpenSSH Server インストール | 鍵認証・Linux混在環境・将来標準 |
| schtasks /s | 管理者権限でのバッチ遠隔起動 | ファイアウォール許可 | SYSTEM権限実行可能・既存スクリプト活用 |
バッチファイルで複数PCに一括コマンドを送信する方法(PsExec活用):PsExecのオプション詳細と実践パターン。
ネットワーク接続の有無を判定して処理を分岐する方法:送信前のping疎通確認の実装方法。
バッチファイルで並列処理を実行する方法:多数のホストへの並列送信パターン。
schtasksコマンドでタスクスケジューラを完全制御する完全ガイド:schtasksコマンドの詳細な使い方。
バッチファイルでエラー通知メールを自動送信する完全ガイド:失敗時のメール・Slack自動通知の実装。

