はじめに
Windowsにて別端末のプログラムを起動する方法を調べたのでまとめておく。
- 方法1:リモートデスクトップ
- 方法2:Telnet
- 方法3:at (タスクスケジューラ)
- 方法4:schtasks (タスクスケジューラ)
- 方法5:PowerShell (WinRM)
- 方法6:WMI
- 方法7:PsExec
条件
いろんな方法があるので一応条件として
- Windowsの標準機能で実現
- スクリプト等は作成せずとにかく簡単に
環境
呼び出す側をローカル、呼び出される側をリモートとしておく。
端末 | OS | IP |
---|---|---|
ローカル | Windows 7 | 192.168.100.1 |
リモート | Windows 7 | 192.168.100.101 |
ここでは、
例としてリモート端末の単純なバッチC:\Remote\run_batch.bat
を起動する状況を考える。
echo Complete > C:\Remote\run.log
記事への補足
-
<user>
はリモート端末側にて有効なユーザ名 -
<pass>
は<user>
のパスワード
方法1:リモートデスクトップ
- リモート端末のデスクトップにログオンしてプログラムを実行する方法
- プログラムを実行するだけなので、今回の用途には不適切
方法2:Telnet
- 簡単に言えばリモートデスクトップのCUI版
- リモートデスクトップ同様、プログラムの実行だけに利用するのは不適切
- 機能を有効化しないと利用できない
リモート端末での準備
- Telnetサーバ の有効化(後述)
- 22番ポートの開放
-
telnet
サービスを開始する - 接続ユーザを
TelnetClients
グループに所属させる
22番ポートはTelnetサーバインストール時に開放されていると思うので、
あとは以下コマンドでOKなはず。
> net start telnet
> net localgroup TelnetClients <user> /add
Telnetサーバ の有効化手順
- [コントロールパネル] の [プログラム] - [プログラムと機能] から [Windowsの機能の有効化または無効化] をクリック
- [Telnet サーバ] をチェック
クライアント端末での準備
- Telnetクライアント の有効化
Telnetクライアント の有効化手順
- [コントロールパネル] の [プログラム] - [プログラムと機能] から [Windowsの機能の有効化または無効化] をクリック
- [Telnet クライアント] をチェック
実行例
telnetでリモート端末にログオンし、直接対象のプログラムを実行するだけ。
> telnet 192.168.100.101
Microsoft Telnet クライアントへようこそ
エスケープ文字は 'CTRL+]' です
パスワード情報を インターネット ゾーンのリモート コンピューターに送信しようとし
ていますが、この操作は安全でない可能性があります。送信しますか? (Y/N):
Welcome to Microsoft Telnet Service
login: <user>
password:
*===============================================================
Microsoft Telnet Server.
*===============================================================
C:\Users\user>C:\Remote\run_batch.bat
C:\Users\user>type C:\Remote\run.log
Complete
ただしちゃんと警告してくれているようにそもそも安全性に難があり。
方法3:at (タスクスケジューラ)
-
at
コマンドを利用して、タスクスケジューラからプログラムを起動する - 開始時間を指定して実行できる(逆に言えば時間を指定する必要がある)
リモート端末での準備
- ファイアウォールにて "ファイルとプリンターの共有" グループを有効化
- 英語版ならgroup名は "File and Printer Sharing"
> netsh advfirewall firewall set rule group="ファイルとプリンターの共有" new enable=yes
クライアント端末での準備
利用ユーザによっては不要かと思われるが、
実行時にアクセスエラーが出る場合はIPCリソースへ接続できるようにしておく。
REM (必要なら) 事前にIPCリソースへ接続
> net use \\192.168.100.101\IPC$ /user:<user>
実行例
at
コマンドではリモート端末側の開始時刻を指定するため、
リモート端末での時刻をnet time
で取得して1分後に指定してみる。
REM サーバの時間
> net time \\192.168.100.101
\\192.168.100.101 の現在の時刻は 2016/12/05 10:10:10 です
REM 1分後に実行
> at \\192.168.100.101 10:11 C:\Remote\run_batch.bat
新しいジョブをジョブ ID = 1 で追加しました。
> at \\192.168.100.101
状態 ID 日付 時刻 コマンド ライン
-------------------------------------------------------------------------------
1 今日 10:11 C:\Remote\run_batch.bat
REM 実行ジョブが無くなっていれば実行完了(成功したかどうかは別)
> at \\192.168.100.101
一覧にエントリが存在しません。
ただしat
コマンドでは存在していないが、リモート端末のタスクスケジューラには残る。
よって消さない限り増えていく。
> at \\192.168.100.101 <ジョブID> /delete
方法4:schtasks (タスクスケジューラ)
-
schtasks
コマンドを利用してタスクスケジューラからプログラムを起動する -
at
コマンドより高機能なので、任意タイミングで実行することもできる
リモート端末での準備
- ファイアウォールにて "スケジュールされたリモート タスク管理" グループを有効化
- 英語版ならgroup名は "Remote Scheduled Tasks Management"
> netsh advfirewall firewall set rule group="スケジュールされたリモート タスク管理" new enable=yes
- 実行したいタスクスケジューラをあらかじめ作成しておいてもよい
クライアント端末での準備
特に不要だった。
実行例
リモート端末に、開始時間を過去日付に指定したタスクを作成しておき、
そのタスクを任意のタイミングで呼び出すことでプログラムを実行する。
REM タスクスケジューラにタスクを作成
> schtasks /Create /S 192.168.100.101 /U <user> /P <pass> /TN sample /SC ONCE /SD 1900/01/01 /ST 00:00 /TR C:\Remote\run_batch.bat
警告: /ST が現時刻よりも早いため、タスクは実行されない可能性があります。
成功: スケジュール タスク "sample" は正しく作成されました。
REM 実行
> schtasks /Run /S 192.168.100.101 /U <user> /P <pass> /TN sample
成功: スケジュール タスク "sample" の実行が試行されました。
実行ユーザの変更など、それなりに細かい制御ができる。
方法5:PowerShell (WinRM)
- PowerShellからWinRMを利用する
リモート端末での準備
- ファイアウォールにて "Windows リモート管理 (HTTP 受信)" を有効化
- 英語版なら規則名は "Windows Remote Management (HTTP-In)"
> netsh advfirewall firewall set rule name="Windows リモート管理 (HTTP 受信)" new enable=yes
クライアント端末での準備
- WinRMサービスの起動
- 接続先のリモート端末を信頼する
作業としてはPowerShellにて以下を実行する
PS> Set-Item wsman:\localhost\Client\TrustedHosts "192.168.100.101" -Concatenate
WinRM サービスの起動
WinRM サービスは現在起動していません。このコマンドを実行すると、WinRM サービスが起動します。
続行しますか?
[Y] はい(Y) [N] いいえ(N) [S] 中断(S) [?] ヘルプ (既定値は "Y"):
WinRM セキュリティの構成。
このコマンドは WinRM クライアントの TrustedHosts の一覧を変更します。TrustedHosts
の一覧内にあるコンピューターは認証されない可能性があります。クライアントはこれらのコンピューターに資格情報を送信する可
能性があります。この一覧を変更しますか?
[Y] はい(Y) [N] いいえ(N) [S] 中断(S) [?] ヘルプ (既定値は "Y"):
実行例
PowerShellにて以下を実行するだけ。
PS> Invoke-Command -ComputerName 192.168.100.101 -Credential <user> {C:\Remote\run_batch.bat}
C:\Users\user\Documents>echo Complete 1>C:\Remote\run.log
方法6:WMI
-
WMIC
コマンドを利用して、WMIが管理する情報を利用する -
WMIC
はWindows XP以降標準で利用可能なコマンドラインツール
リモート端末での準備
- ファイアウォールにて "Windows Management Instrumentation (WMI)" グループを有効化
> netsh advfirewall firewall set rule group="Windows Management Instrumentation (WMI)" new enable=yes
クライアント端末での準備
特に不要だった。
実行例
> WMIC /NODE:192.168.100.101 /user:<user> /password:<pass> process call create "C:\Remote\run_batch.bat"
WMIC
自体はさまざまなWindows の状態を取得出来るツールなので、
もっと別の目的で活用してあげたい。
方法7:PsExec
- Stack Overflow の回答でも一番多い回答がこのPsExecを利用する方法
- 標準で入っていないのでタイトルと合わないが、Windows純正のソフトでダウンロードするだけで利用できる
- ローカルファイルをコピーすると同時にリモート実行など、他に無いちょっとクールな使い方もできる
リモート端末での準備
ファイアウォールにて以下を開放しておく必要がある。
- 135/tcp(RPCエンドポイント・マッパー)
- 445/tcp(ダイレクト・ホスティングSMB)
- 1025~65535/tcp(RPC動的ポート)
コマンドでやるならこんな感じ
> netsh advfirewall firewall add rule name=PsExec dir=in action=allow localport=rpc-epmap protocol=tcp program= %windir%\system32\svchost.exe
> netsh advfirewall firewall add rule name=PsExec dir=in action=allow localport=445 protocol=tcp
> netsh advfirewall firewall add rule name=PsExec dir=in action=allow localport=rpc protocol=tcp program=%SystemRoot%\system32\services.exe
他でやっているように既存の規則を有効化してやっても良いが、新規にルールを追加すれば後から無効化するのが楽。
netsh advfirewall firewall set rule name=PsExec new enable=no
みたいな感じで。
クライアント端末での準備
以下よりPsExecをダウンロードし、適当な場所に展開する。
https://technet.microsoft.com/ja-jp/sysinternals/pxexec.aspx
実行例
一番今回の目的にあっていると思われる方法。
> PsExec.exe -u <user> -p <pass> \\192.168.100.101 C:\Remote\run_batch.bat
PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
C:\Windows\system32>echo Complete 1>C:\Remote\run.log
C:\Remote\run_batch.bat exited on 192.168.100.101 with error code 0.
またv2.1以降であれば、通信自体も暗号化されているとのこと。