分辨率变化时重启 explorer

提示:因为 windows 的玄学问题,每个人启动的时候 windows 发生的事件可能不同,本文仅供参考和提供思路。

(240101 更新) 频繁重启 explorer 可能会造成 explorer 最终无法启动成功的问题,如遇到该问题,建议不要使用本方法。

起因

我经常在不同设备远程登录自己家电脑,然后发现:一旦远程设备的分辨率和缩放和自家的不同,就会导致窗口最大化后布局错乱,解决方法就是重启 explorer。另外我还装有一个 desktop ticket,专门拿来看 rss 新闻的,重启 explorer 的时候不重启这个软件的话也会导致最大化的时候窗口被这条东西挡着,所以也一并重启。

最大化窗口布局错乱

查看事件

参考文章:通过windows日志查看器查看系统登陆日志_windows查看登录日志_g1bbs_的博客-CSDN博客

参考文章可知,真正的登录事件是 4648。不过认真看进去的话,登录一次会出现两个 4648,因为一个是 scvhost 进程的登录,一个是 lsass 进程的登录,实际上可以看作一个,所以我们监听其中一个事件就可以了。我们这里监听 scvhost。

先来到事件查看器->windows 日志->安全,点右边的筛选试图,切换到 xml 页签,勾选手动编辑查询复选框,在输入框中输入以下内容:

1
2
3
4
5
6
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[(EventID=4648)]] and
*[EventData[Data[@Name='ProcessName']='C:\Windows\System32\svchost.exe']]</Select>
</Query>
</QueryList>

查看结果:

用一段事件后如果发现该计划任务运行过于频繁,有可能是因为已经有许多计划任务在远程连接时在调用(计划任务运行时也会用到 scvhost 进程),我们可以改成用 lsass.exe 进程的日志进行监听;如果监听 lsass 的日志发现某些时候远程过来任务没有出发,因为 lsass 没有登录,我们可以把 rdp 的 1149 事件也加入脚本中,最后的结果像这样:

1
2
3
4
5
6
7
8
9
10
11
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[(EventID=4648)]] and
*[EventData[Data[@Name='ProcessName']='C:\Windows\System32\lsass.exe']]</Select>
</Query>
<Query Id="1" Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational">
<Select Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational">
*[System[(EventID=1149)]]
</Select>
</Query>
</QueryList>

编写重启程序脚本

脚本的路径放在 D:\git\login_resolution.ps1 中,可自定义。powershell 可以用 windows 自带的工具调试,bat 不行,但 powershell 重启 explorer 会自动启一个资源管理器窗口,以前用过的 bat 不会,算是一个小缺点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 定义存储分辨率信息的文件路径
$filePath = "D:\login_resolution.txt"

# 如果文件不存在,创建一个空的文件
if (-not (Test-Path -Path $filePath)) {
$null | Out-File -FilePath $filePath
}

# 从文件中读取以前的分辨率信息
$previousResolution = Get-Content -Path $filePath

# 默认为System.Object[]类型,需要转换成string类型
$previousResolution2 = $previousResolution | Out-String

# 获取当前分辨率信息并直接转换为字符串
$currentResolution = Get-WmiObject -Class Win32_VideoController | Select-Object -Property CurrentHorizontalResolution, CurrentVerticalResolution
$currentResolution2 = $currentResolution | Out-String

$previousResolutionTrim = $previousResolution2.Trim()
$currentResolutionTrim = $currentResolution2.Trim()

if ($currentResolutionTrim -ne $previousResolutionTrim) {
# 关闭 explorer.exe 和 DesktopTicker.exe
Stop-Process -Name "explorer" -Force
Stop-Process -Name "DesktopTicker" -Force

# 启动 explorer.exe 和 DesktopTicker.exe
Start-Process "explorer.exe"
Start-Process "C:\Program Files\Desktop Ticker\DesktopTicker.exe"

# 等待一段时间
Start-Sleep -Seconds 4

# 更新文件中的分辨率信息,并附加到文件末尾
$currentResolutionTrim | Out-File -FilePath $filePath -Force
}

编辑计划任务

进入任务计划程序,创建任务,填入名字。触发器里面,点击新建,开始任务选择发生事件时,设置选择自定义,点击新建事件筛选器后,出现的界面就是上一步的界面,此处略过不谈。

转到操作处,选择新建,操作选启动程序,程序或脚本输入 powershell,参数输入 ps1 的路径,点确定即可。

再点确定完成任务生成。如果报错「任务 远程重启 explorer 出错。错误消息: 一个或多个指定的参数无效。」,来到常规->安全选项->更改用户或组,输入账号名,点检查名称,会自动补全,点确定,即可解决问题。

另外如果重启时不想看到弹出的窗口,可以修改启动程序时添加的参数为 -WindowStyle Hidden -File "D:\git\login_resolution.ps1"

如果监听的是 scvhost.exe,务必不要把设置里的「如果此任务已运行,以下规则适用」从「请勿启动新实例」改为「停止现有实例」,否则会无限重启 explorer 导致锁死。