1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PowerShellでRDP/VNC接続時のマルチモニター指定を自動化する

Posted at

マルチモニター環境でリモートデスクトップ(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
  1. qwinstaでリモートセッション一覧を取得
  2. GUIでセッション選択(1つの場合は自動選択)
  3. mstsc /shadowで接続
  4. 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座標でソートすることで「左」「右」を物理位置に基づいて判定

参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?