PowerShell控制台与ISE中Screen Bounds不一致致多显示器黑屏异常求助
解决PowerShell控制台/计划任务中System.Windows.Forms.Screen Bounds返回错误的问题
这个问题我之前也碰到过,根源在于PowerShell控制台(包括计划任务中运行的PowerShell进程)默认没有启用高DPI感知,而PowerShell ISE是自带这个特性的。这就导致System.Windows.Forms.Screen.Bounds返回的是经过系统DPI缩放后的虚拟坐标,而非显示器的实际物理像素,最终你的黑屏窗口只能覆盖屏幕一半。
下面是几种可行的解决方法:
1. 脚本内临时启用高DPI感知(推荐,适用于所有场景)
在加载System.Windows.Forms之前,通过调用Win32 API强制设置进程的高DPI感知。这样不管是在控制台还是计划任务中运行,都能获取正确的屏幕边界:
# 定义调用Win32 DPI感知API的辅助类 Add-Type @" using System; using System.Runtime.InteropServices; public class DpiHelper { // Windows 8.1+ 支持的每显示器DPI感知 [DllImport("user32.dll", SetLastError = true)] public static extern bool SetProcessDpiAwareness(int awareness); // 旧版系统兼容的全局DPI感知 [DllImport("user32.dll")] public static extern bool SetProcessDPIAware(); } "@ # 优先设置每显示器DPI感知(适用于Win10/11),失败则回退到全局感知 try { # 2 = PROCESS_PER_MONITOR_DPI_AWARE,支持多显示器不同DPI if (-not [DpiHelper]::SetProcessDpiAwareness(2)) { [DpiHelper]::SetProcessDPIAware() } } catch { [DpiHelper]::SetProcessDPIAware() } # 现在加载Windows Forms并获取屏幕信息 Add-Type -AssemblyName System.Windows.Forms $screens = [System.Windows.Forms.Screen]::AllScreens # 验证:输出每个屏幕的实际分辨率 foreach ($screen in $screens) { Write-Host "显示器 $($screen.DeviceName) 实际Bounds: $($screen.Bounds.Width)x$($screen.Bounds.Height)" }
运行这段代码后,你会发现Bounds返回的数值和ISE中完全一致,此时你的黑屏逻辑就能正确覆盖整个屏幕了。
2. 永久设置PowerShell控制台的高DPI感知
如果你经常在控制台运行这类脚本,可以修改PowerShell快捷方式的属性,永久启用高DPI缩放替代:
- 右键PowerShell快捷方式 → 选择「属性」
- 切换到「兼容性」标签页
- 勾选「替代高DPI缩放行为」,在下拉菜单中选择「应用程序」
- 点击「确定」保存设置
这样每次打开PowerShell控制台,进程都会自动启用高DPI感知,无需在脚本中重复添加代码。
3. 计划任务场景的额外注意事项
计划任务中运行的PowerShell进程默认也没有高DPI感知,所以必须在脚本开头加入方法1中的DPI感知代码(因为计划任务无法修改快捷方式属性)。另外,确保计划任务的配置:
- 如果选择「不管用户是否登录都要运行」,建议勾选「以最高权限运行」,避免权限不足导致API调用失败
- 确保任务的「操作」中调用的是
powershell.exe,并传入正确的脚本路径参数
内容的提问来源于stack exchange,提问作者Simon B
相关产品推荐
相关产品推荐

