win11添加开机自启动脚本实现网卡异常自动重启

本文最后更新于 2025年4月1日 下午

背景

两台主机使用网线互联,使用Input Directorv2.2实现键鼠共享,但是由于其中一台机器某些软件原因有时候会掐断导致ping失败网络不通,共享键鼠中断,解决办法是禁用网卡后重启,但是每次重置都需要手动操作,所以写了一个脚本实现自动检测网络不通,自动重启网卡。

代码

net_monitor.py

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import os
import time
import subprocess
from subprocess import Popen, PIPE, STARTUPINFO, STARTF_USESHOWWINDOW
import logging

# 配置参数
# 目标 IP 地址
TARGET_IP = "192.168.10.2"
# 网络接口名称
NIC_NAME = "share"
# 最大重试次数
MAX_RETRIES = 10
# 单次 ping 超时时间(秒)
PING_TIMEOUT = 1
# 检查间隔(秒)
CHECK_INTERVAL = 1
# 日志文件绝对路径
LOG_FILE = "net_monitor.log"
# 最大日志文件大小(1MB)
MAX_LOG_SIZE = 1024 * 1024

# 初始化日志记录器(新增文件大小监控)
def setup_logger():
# 创建日志记录器
logger = logging.getLogger(__name__)
# 设置日志级别为 INFO
logger.setLevel(logging.INFO)

# 自定义文件处理器(达到 1MB 时清空)
class TruncatingFileHandler(logging.FileHandler):
def emit(self, record):
# 检查日志文件是否存在且大小超过最大限制
if os.path.exists(self.baseFilename) and os.path.getsize(self.baseFilename) > MAX_LOG_SIZE:
# 清空日志文件
with open(self.baseFilename, 'w') as f:
f.truncate()
# 调用父类的 emit 方法记录日志
super().emit(record)

# 创建自定义文件处理器
handler = TruncatingFileHandler(LOG_FILE, encoding='utf-8')
# 定义日志格式
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
# 为处理器设置日志格式
handler.setFormatter(formatter)
# 为日志记录器添加处理器
logger.addHandler(handler)
return logger

# 初始化日志记录器
logger = setup_logger()
# 上一次的日志消息
last_log_message = None

# 记录操作日志(带文件大小检查)
def log_action(message):
global last_log_message
# 如果最新日志是网络连接正常且和上一条日志相同,仅更新时间
if message == "网络连接正常。" and message == last_log_message:
# 读取日志文件的所有行
with open(LOG_FILE, 'r', encoding='utf-8') as f:
lines = f.readlines()
# 如果日志文件有内容
if lines:
# 获取最后一行
last_line = lines[-1]
# 生成新的时间戳
timestamp = logging.Formatter('%(asctime)s').format(logging.LogRecord(
name=__name__,
level=logging.INFO,
pathname='',
lineno=0,
msg='',
args=(),
exc_info=None
))
# 生成新的最后一行日志
new_last_line = f"{timestamp} - INFO - {message}\n"
# 更新最后一行日志
lines[-1] = new_last_line
# 将更新后的日志写回文件
with open(LOG_FILE, 'w', encoding='utf-8') as f:
f.writelines(lines)
else:
# 记录日志消息
logger.info(message)
# 更新上一次的日志消息
last_log_message = message

# 检测目标主机是否可达
def ping_host(ip):
try:
# 执行 ping 命令,隐藏 ping 窗口
result = Popen(f'ping -n 1 -w {int(PING_TIMEOUT * 1000)} {ip}',
shell=True, stdout=PIPE, stderr=PIPE,
creationflags=0x08000000)
# 获取 ping 命令的输出
output = result.communicate()[0].decode('gbk', errors='ignore')
# 判断输出中是否包含 TTL 信息
return 'TTL=' in output
except Exception as e:
# 记录 ping 错误信息
log_action(f"Ping 失败: {str(e)}")
return False

# 检查网卡是否已断开连接
def is_nic_disconnected(nic_name):
try:
# 创建启动信息对象,隐藏控制台窗口
si = STARTUPINFO()
si.dwFlags |= STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE # 隐藏窗口

result = subprocess.Popen(
f'netsh interface show interface "{nic_name}"',
shell=True,
stdout=PIPE,
stderr=PIPE,
startupinfo=si, # 使用配置好的启动信息
creationflags=subprocess.CREATE_NO_WINDOW # 额外保险(旧版Python兼容)
)
output = result.communicate()[0].decode('utf-8', errors='ignore')
print(output)
return "已断开连接" in output

except Exception as e:
log_action(f"检查网卡状态出错: {str(e)}")
return False

# 重启网络接口
def restart_nic(nic_name):
try:
# 记录尝试重启网络接口的信息
log_action("正在尝试重启网络适配器...")
# 禁用网络接口
os.system(f'netsh interface set interface "{nic_name}" admin=disable >nul 2>&1')
# 等待 2 秒
time.sleep(2)
# 启用网络接口
os.system(f'netsh interface set interface "{nic_name}" admin=enable >nul 2>&1')
# 记录网络接口重启成功的信息
log_action("网卡重启成功。")
return True
except Exception as e:
# 记录网络接口重启失败的信息
log_action(f"重启网卡失败: {str(e)}")
return False

# 主函数
def main():
# 连续失败次数
failure_count = 0
while True:
# 检测目标主机是否可达
if not ping_host(TARGET_IP):
# 失败次数加 1
failure_count += 1
# 记录 ping 失败信息
log_action(f"Ping 失败。当前连续失败次数: {failure_count}/{MAX_RETRIES}")
# 如果连续失败次数达到最大重试次数
if failure_count >= MAX_RETRIES:
# 检查网卡是否已断开连接
if is_nic_disconnected(NIC_NAME):
log_action("网卡已断开连接,跳过重启操作。")
else:
# 重启网络接口
success = restart_nic(NIC_NAME)
# 记录重启结果
log_action(f"重启 {'成功' if success else '失败'}")
# 重置失败次数
failure_count = 0
else:
# 重置失败次数
failure_count = 0
# 记录网络连接正常的信息
log_action("网络连接正常。")
# 等待指定的检查间隔时间
time.sleep(CHECK_INTERVAL)

if __name__ == "__main__":
try:
# 执行主函数
main()
# print(is_nic_disconnected(NIC_NAME))
except Exception as e:
# 记录程序终止信息
log_action(f"程序终止: {str(e)}")
# pyinstaller --onefile -w --uac-admin --noconfirm net_monitor.py

net_monitor.bat

1
2
3
@echo off
cd /d "C:\net_monitor"
start /b pythonw.exe net_monitor.py

设置开机自启动

打开”开始菜单” -> 输入”任务计划程序” -> 选择”创建任务”
常规选项卡:

  • 输入任务名称:”net_monitor”
  • 选择运行用户:”当前用户”
  • 选择运行方式:”最高权限”
  • 勾选”无论用户是否登录都要运行”
  • 勾选”隐藏窗口”
  • 配置win10
    触发器选项卡:
  • 选择”新建”
  • 选择”启动时”
    操作选项卡:
  • 选择”新建”
  • 选择”启动程序”
  • 选择”程序或脚本”,并选择”net_monitor.bat”
    确定创建任务

win11添加开机自启动脚本实现网卡异常自动重启
https://xinhaojin.github.io/2025/04/01/win11添加开机自启动脚本实现网卡异常自动重启/
作者
xinhaojin
发布于
2025年4月1日
更新于
2025年4月1日
许可协议