我在网上搜索了这个问题的解决方案,但无济于事。我需要将特定命令的消息框输出分配给变量。命令是mstsc.exe /l
。对于背景,此命令将可用于 RDP 会话的屏幕的 ID 列到 Windows 消息框。我想将此输出捕获为某种字符串,以便我可以解析它以获取显示器的 ID。
输出mstsc /l
应类似于此,并被分配给一个变量:
0:1920 x 1080; (0,0, xxxx, yyyy),
1:1920 x 1080; (0,0, xxxx, yyyy),
2:1920 x 1080; (0,0, xxxx, yyyy)
任何帮助都将非常感激。
答案1
不确定是否有办法直接捕获mstsc -l
框,但您也可以使用 powershell 并进行一些研究,以直接从 .net 以编程方式利用所需的值
Add-Type -AssemblyName System.Windows.Forms
$Array = ([System.Windows.Forms.Screen]::AllScreens|sort -Property {$_.Displayname} )
($Array[0].DeviceName).Split('\\')[-1]
$Array[0].Bounds.Width
$Array[0].Bounds.Height
$Array[0].Bounds.Left
$Array[0].Bounds.Top
($Array[0].Bounds.Right)-1
($Array[0].Bounds.Bottom)-1
($Array[1].DeviceName).Split('\\')[-1]
$Array[1].Bounds.Width
$Array[1].Bounds.Height
$Array[1].Bounds.Left
$Array[1].Bounds.Top
($Array[1].Bounds.Right)-1
($Array[1].Bounds.Bottom)-1
($Array[2].DeviceName).Split('\\')[-1]
$Array[2].Bounds.Width
$Array[2].Bounds.Height
$Array[2].Bounds.Left
$Array[2].Bounds.Top
($Array[2].Bounds.Right)-1
($Array[2].Bounds.Bottom)-1
编辑:不幸的是,我没有一个显示 1、2 或 3 以外的数字的系统可供测试,但您可以将 .DeviceName 添加到输出中以显示数组中的显示编号,作为参考,这应该匹配,但 MSTSC /l 信息从 0 开始索引。如果没有,那么我认为它目前可能无法通过 .net 获得
答案2
此示例使用Microsoft UI 自动化
Add-Type -AssemblyName 'UIAutomationClient'
#Start mstsc.exe with the argument /l, retain a process reference in $mstscProc
$mstscProc = Start-Process -FilePath 'mstsc.exe' -ArgumentList '/l' -PassThru
try {
$handle = $null
#MainWindowHandle sometimes returns 0, this while loop is a workaround
while ((-not $mstscProc.HasExited) -and ($null -eq $handle))
{
Start-Sleep -Milliseconds 500
$mstscProc.Refresh()
if ($mstscProc.MainWindowHandle -ne 0)
{
$handle = $mstscProc.MainWindowHandle
}
}
$cTrue = [System.Windows.Automation.PropertyCondition]::TrueCondition
#Get the root element of the mstsc.exe process by handle
$root = [System.Windows.Automation.AutomationElement]::FromHandle($handle)
$rawText = $root.FindAll("Children", $cTrue) |
Select-Object -ExpandProperty Current |
# I used inspect.exe from the WinSDK to determine the AutomationId for the element containing the text
Where-Object AutomationId -ieq 'ContentText' |
Select-Object -ExpandProperty Name
}
finally {
$mstscProc | Stop-Process -Force
}
#split the raw text an process one line at a time
$rawText -split '\r?\n' | ForEach-Object {
$parts = @()
try {
#Convert the line format "0: 1920 x 1080; (0, 0, 1919, 1079)" into numbers seperated by , then split
$parts = @($_.replace(':', ',').replace(' x ', ',').replace(';', ',').replace('(', '').replace(')', '').replace(' ', '').Trim() -split ',')
}
catch {
#if any exceptions occur we assume the line is malformed
$_ | Write-Verbose
}
if ($parts.Length -eq 7) {
# a wellformed line should have 7 parts
$properties = [ordered]@{
Index = [int]$parts[0]
Width = [int]$parts[1]
Height = [int]$parts[2]
Left = [int]$parts[3]
Top = [int]$parts[4]
Right = [int]$parts[5]
Bottom = [int]$parts[6]
}
New-Object -TypeName psobject -Property $properties | Write-Output
}
}
更新
@DarkDiamond,回答你的问题:
- 我已经包含了代码注释,但概要如下:
- 启动 mstsc.exe /l 并使用进程对象获取主窗口句柄
- 使用主窗口句柄(通过 UIAutomationClient)搜索包含监视器定义文本的控件
- 存储监视器定义文本并停止 mstsc.exe 进程
- 解析监视器定义文本并返回每个监视器的 PSObject
- 我写了脚本,但我用了一个与通过 PowerShell 进行 UI 自动化
- 上述解决方案(使用 [System.Windows.Forms.Screen]::AllScreens)并非在所有情况下都有效,因为:
- mstsc.exe /l 返回的显示器索引与 DisplayName 不一致或按连续顺序排列(即 0、1、2),在我当前的电脑上,显示器索引为 0、3、4,其他用户报告显示器索引在重启后重新编号。
- 监视器索引中的这种不一致意味着我无法为非技术用户创建每次都一致跨越相同监视器的 rdp 设置文件,因此该脚本作为更大的 PS 模块的一部分开发,以动态生成无需用户发明即可工作的机器特定的 rdp 配置文件。
- 我希望如果其他开发人员/管理员有类似的要求,上面的代码片段将会很有价值。
答案3
我基于 @djwork 编写的出色脚本(谢谢!)添加了功能,以便创建一个新的临时 .rdp 文件,其中包含所需的监视器索引子集并启动它。假设您在这里完成相同的任务,请执行以下操作。
- 从@djwork 的答案中获取脚本
- 修改第 33 行,将结果存储到
$monitors
变量中:$monitors = $rawText -split '\r?\n' | ForEach-Object {
- 在某处创建一个模板 .rdp 文件,其中包含以下行
selectedmonitors:s:0,1
- 将此代码添加到脚本末尾:
$primaryMonitor = $monitors | ? { $_.Left -eq 0 }
$secondaryMonitor = $monitors | ? { $_.Left -gt 0 }
$replaceString = "selectedmonitors:s:{0},{1}" -f $primaryMonitor.Index, $secondaryMonitor.Index
$newRdpContent = (gc <path to template>.rdp) -replace "selectedmonitors:s:0,1", $replaceString
$tempFile = Join-Path $env:TEMP "temp.rdp"
$newRdpContent > $tempFile
start $tempFile
现在,您只需执行此脚本即可获取所需的索引,创建一个新的临时 rdp 文件并启动它。此示例假设您有 3 个显示器,并且只想将最右边的两个用于 RDP。您可以根据自己的具体情况进行自定义