マルチモニター環境でリモートデスクトップ(RDP)やVNC接続を行う際、「左モニターに表示したい」「右モニターで全画面表示したい」といった要望は多いと思います。
本記事では、PowerShellスクリプトでこれを自動化する方法と、調査過程で発見したmstscのモニターID算出法則について解説します。
TL;DR
-
mstsc(RDP)のモニターID =
DISPLAY番号 - 1 -
Screen.AllScreensのインデックスとは一致しない - RealVNC Viewerは
Screen.AllScreensのDeviceNameをそのまま使用
問題:モニターIDの不一致
マルチモニター環境でRDP接続時に特定のモニターを指定するには、.rdpファイルのSelectedMonitors設定を使います。
SelectedMonitors:s:1
Use multimon:i:0
しかし、このモニターIDがどのように決まるかは公式ドキュメントに明記されておらず、試行錯誤が必要でした。
調査結果
mstsc /lコマンドでモニター一覧を確認できます(GUIダイアログが表示される):
0: 2560 x 1440; (4000, 0, 6559, 1439) ← X=4000 (右端)
1: 2560 x 1440; (0, 0, 2559, 1439) ← X=0 (左端)
2: 1440 x 2560; (2560, -465, 3999, 2094) ← X=2560 (中央)
一方、Screen.AllScreens(.NET)で取得すると:
Index 0: X=0 (\\.\DISPLAY2) ← 左端
Index 1: X=4000 (\\.\DISPLAY1) ← 右端
Index 2: X=2560 (\\.\DISPLAY3) ← 中央
順序が全く異なる!
発見した法則
調査の結果、以下の法則を発見しました:
mstsc ID = DISPLAY番号 - 1
| DeviceName | mstsc ID |
|---|---|
\\.\DISPLAY1 |
0 |
\\.\DISPLAY2 |
1 |
\\.\DISPLAY3 |
2 |
これにより、Screen.AllScreensから取得したDeviceNameを使って、正しいmstsc IDを算出できます。
RDP.ps1 - リモートデスクトップ接続ラッパー
使い方
# 基本使用法
RDP.ps1 # デフォルトIPに全モニターで接続
RDP.ps1 100 # 指定IPに右モニターで接続
RDP.ps1 100 L # 左モニターで接続
RDP.ps1 100 R # 右モニターで接続
RDP.ps1 100 M # 中央モニターで接続(3台以上)
RDP.ps1 100 B # 全モニターで接続
RDP.ps1 100 S # シャドウモード(セッション選択)
RDP.ps1 100 R User # ユーザー名指定
モニター指定オプション
| オプション | 説明 |
|---|---|
L または 1
|
左モニター(X座標最小) |
R または 2
|
右モニター(X座標最大) |
M または 3
|
中央モニター |
B または 0
|
全モニター |
S |
シャドウモード |
コア実装
# DISPLAY番号からmstsc IDを算出
Add-Type -AssemblyName System.Windows.Forms
$allScreens = [System.Windows.Forms.Screen]::AllScreens
$monitors = @()
foreach ($s in $allScreens) {
# DeviceNameからDISPLAY番号を抽出 (例: "\\.\DISPLAY2" -> 2)
$displayNum = [regex]::Match($s.DeviceName, 'DISPLAY(\d+)').Groups[1].Value
$mstscId = [int]$displayNum - 1
$monitors += [PSCustomObject]@{
MstscIndex = $mstscId
Left = $s.Bounds.X
DeviceName = $s.DeviceName
}
}
# X座標でソートして左右を判定
$sortedMonitors = @($monitors | Sort-Object { $_.Left })
$leftMonitor = $sortedMonitors[0]
$rightMonitor = $sortedMonitors[-1]
# RDPファイルを更新
$content = $content -replace "SelectedMonitors:s:[^\r\n]*", "SelectedMonitors:s:$($leftMonitor.MstscIndex)"
シャドウモード
シャドウモードでは、リモートPCのアクティブセッションを選択して画面共有できます。
RDP.ps1 100 S
-
qwinstaでリモートセッション一覧を取得 - GUIでセッション選択(1つの場合は自動選択)
-
mstsc /shadowで接続 - WTS APIでリモート解像度を取得し、ウィンドウサイズを自動調整
VNC.ps1 - RealVNC Viewer接続ラッパー
使い方
VNC.ps1 100 # 右モニター、フルスクリーン、100%
VNC.ps1 100 L # 左モニター、フルスクリーン、100%
VNC.ps1 100 R A # 右モニター、フルスクリーン、Auto Scaling
VNC.ps1 103 # 右モニター、ウィンドウモード、100%
コア実装
RealVNC Viewerは-MonitorオプションでDeviceNameを直接指定できます:
Add-Type -AssemblyName System.Windows.Forms
$screens = [System.Windows.Forms.Screen]::AllScreens
# X座標でソートして左右を判定
$leftMonitor = ($screens | Sort-Object { $_.Bounds.X } | Select-Object -First 1).DeviceName
$rightMonitor = ($screens | Sort-Object { $_.Bounds.X } -Descending | Select-Object -First 1).DeviceName
# VNC Viewerを起動
$argList = @(
$hostName,
"-FullScreen=1",
"-Scaling=100%",
"-Monitor=`"$rightMonitor`""
)
Start-Process -FilePath "VNC-Viewer-Windows-64bit.exe" -ArgumentList ($argList -join " ")
モニターIDの対応表
| 名称 | 説明 | 算出方法 |
|---|---|---|
| WinGDI | Windows設定画面の番号 | DISPLAY番号 |
| mstsc | RDP SelectedMonitors | DISPLAY番号 - 1 |
| VNC | RealVNC Viewer |
DeviceNameそのまま |
実測例:
| 物理位置 | DISPLAY番号 | mstsc ID | Screen.AllScreens Index |
|---|---|---|---|
| Left (X=0) | DISPLAY2 | 1 | 0 |
| Middle | DISPLAY3 | 2 | 2 |
| Right (X=4000) | DISPLAY1 | 0 | 1 |
まとめ
- mstscのモニターIDは
DISPLAY番号 - 1で算出できる -
Screen.AllScreensのインデックスとは異なるので注意 - RealVNC ViewerはDeviceNameを直接使用可能
- X座標でソートすることで「左」「右」を物理位置に基づいて判定