住处的路由器经过一番折腾,自带访问国际互联网的环境,而其他地方的网络当然不会有这个东西了,这就需要在电脑上启动代理。每次搬电脑都要开关代理很麻烦,于是心生一计,使用Windows自带的十分完善的任务计划功能,来实现根据网络环境的代理软件自动开关功能。理论上这同时适用于Clash、ShadowsocksR等代理软件。
在Windows 11 build 22000.282测试通过,理论上近几个大版本的Windows 10也同样适用。
自动打开代理软件
这一部分讲述了在连接到某一特定SSID的WiFi网络时如何启动代理,以Shadowsocks为例。
使用Windows搜索“计划任务”或者“taskschd”可以找到任务计划程序。
点击右侧“创建任务”,随便起个名字。
切换到“触发器”选项卡,新建“发生事件时”触发器,“开始任务”选择“发生事件时”,“日志”选择“Microsoft-Windows-NetworkProfile/Operational”,“源”选择“NetworkProfile”,“事件ID”填写“10000”,其他不变,如图。
切换到“操作”选项卡,新建操作,在“程序或脚本”栏里浏览并选择你的Shadowsocks主程序,其他不变,点击确定。
再切换到“条件”选项卡,选中“只有在以下网络连接可用时才启动”,选择你希望打开Shadowsocks的网络环境。某些时候,网络SSID并不等于环境名称,这时最好查看“找到真正的网络名称”部分以确保选择正确。这样相当于监听每一次网络环境改变事件,再检查当前网络环境,如果符合条件则启动。同时还需要关闭”只有在计算机使用交流电源时才启动此任务“,毕竟能拿着电脑到处跑的人应该会经常用电池吧。
点击确定,即可完成设置。
找到真正的网络名称
有些时候,你可能会遇到和我一样的情况:明明想找一个名为xxx的WiFi,但在“只有在以下网络连接可用时才启动”下拉框中却发现了形如“xxx 1”“xxx 2”之类的网络。如果没有这种情况,那很好,你不用看这一小节了;否则,需要打开“适配器选项”窗口来确定真正的网络名称。
首先要连接目标网络,然后根据操作系统不同,有不同的步骤。
对于Windows 10,在任务栏网络图标右键,选择“打开网络和Internet设置”,然后点击“更改适配器选项”;而对Windows 11,要打开设置-网络 & Internet-高级网络设置-更多网络适配器选项。会弹出如下图的窗口。
这里再骂一次微软,Windows 10适配器选项页面的高分屏优化都比11好,起码字体没毛边。
这里根据你的情况寻找你的网络名称,比如我的是“PDCN_5G 7”。
自动关闭代理软件
仍然以Shadowsocks为例。这个实现起来相对麻烦些,因为任务计划没有设定关闭程序的操作。好在我们有PowerShell,所以我们可以使用PoweShell脚本来结束进程。
新建一个文本文档,将扩展名改为.ps1,文件名任取。然后,在里面粘贴以下内容(假设你的Shadowsocks设定的是PAC模式):
Write-Output "Stopping Shadowsocks"
Get-Process | Where-Object {$_.ProcessName.Contains("Shadowsocks") } | Stop-Process
Write-Output "Trying to delete proxy registry"
Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name "AutoConfigURL"
然后保存。
按上面的步骤创建一个新任务。“触发器”与上面相同。
在“操作”-“程序或脚本”的“添加参数”栏填入刚刚新建的PowerShell脚本路径,“程序或脚本”填入“pwsh.exe”(如果你安装了新版PowerShell Core)或“powershell.exe”(通用,但是是老版本),其他不变,确定。如下图:
“条件”-“只有在以下网络连接可用时”改为你希望自动关闭Shadowsocks的网络环境。
点击确定,即可完成设置。不想了解细节的读者,不需要读本节中下面的部分。
我们都知道,要关闭Shadowsocks,当然要结束Shadowsocks.exe。它运行的时候,还会同时启动Privoxy透明代理,但结束主程序的时候它也会一起关闭,所以没有必要考虑这个。
如果你使用的是PAC代理模式而不是全局代理,有时系统设置-网络 & Internet -代理-使用设置脚本的开关并不会关闭,部分影响网络浏览。这个开关由注册表键值HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\AutoConfigURL所管理,如果存在则代表这个开关打开,并将PAC代理指向它的值,键值字符串代表设置的代理服务器地址。那么,我们增加一条命令将这个键删掉,就可以保证彻底关闭了。
进阶:自动检测网络环境,开关代理
这部分以v2rayN为例。如果你经常在多个网络环境之间穿梭,每个网络条件不同(甚至同一个网络路由器端的梯子都有可能挂掉),上面的那个办法就不是那么好用了。既然我们写了PowerShell脚本,不妨一步到位,直接检测网络环境。
首先你需要新建一个在网络环境改变的时候就调用的任务计划,而不需要特定网络连接条件,可以参照“自动打开代理”部分。
然后新建一个PowerShell脚本,少废话,上代码。
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -Name ProxyEnable -Value 0 #首先禁用系统代理,防止对检测造成影响
$url = "http://clients3.google.com/generate_204"
$req = [system.Net.WebRequest]::Create($url)
$proxyActive = Get-Process v2rayN -ErrorAction SilentlyContinue #检测v2rayN是否运行,后面那个param是在它没有运行的情况下继续执行脚本
try {
$res = $req.GetResponse() #获取HTTP状态码
}
catch [System.Net.WebException] {
$res = $_.Exception.Response
}
if ($res.StatusCode -eq "NoContent") {
#能够直连国际互联网
Write-Output "Google Is Connected, Stopping Proxy"
Get-Process | Where-Object { $_.ProcessName.Contains("v2ray") } | Stop-Process
}
else {
#不能直连国际互联网
if ($null -eq $proxyActive) {
# 代理未运行,打开代理
Write-Output "Cannot connect to Google, Starting Proxy"
&"Your\Path\To\v2rayN.exe"
}
else {
# 代理软件已运行,启用系统代理即可
Write-Output "Re-enabling Proxy"
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -Name ProxyEnable -Value 1
}
}
将里面的 Your\Path\To\v2rayN.exe
替换为v2rayN.exe路径,然后让那个任务计划在满足条件时执行它。
v2rayN采用的是系统代理方案,把v2rayN.exe结束掉,会自动结束xray.exe,但要手动控制系统代理。控制它的注册表项是 HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable,类型为DWORD,1为开启,0为关闭。
显而易见,http://clients3.google.com/generate_204是在墙外的网站。如果访问正常,这个页面会返回一个HTTP 204 NoContent,否则res会是$null。
参考文献
windows – How to launch a command on network connection/disconnection? – Super User
利用Windows计划任务定时关闭程序 – 蜂鸣器 (fmqcloud.com)
一键打开关闭ie代理 – 问题求助 – 小众软件官方论坛 (appinn.net)
How to Get, Edit, Create and Delete Registry Keys with PowerShell (netwrix.com)
如何在powershell中让运行的程序停止_百度知道 (baidu.com)
设定Windows计划任务定期执行PowerShell脚本【图文】_StanlyCheng_51CTO博客
尝试了第一个方法后,发现断开相应的网络也会自动关闭触发时打开的程序,是windows变智能了么?
不知道,我是一次全都设置完了……