news 2026/10/23 20:26:32

Python批量远程关机脚本:Windows局域网运维实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python批量远程关机脚本:Windows局域网运维实战

简介:这是一份面向IT运维人员与Python学习者的Windows远程批量关机脚本资源,针对多台设备统一关机、故障排查与日常维护场景,提供可直接参考的自动化实现思路。压缩包共3个文件,以1个py脚本和2个txt说明文档为主,脚本承载核心的WMI远程连接与关机逻辑,txt则用于记录IP列表与使用说明,整体仅923B,轻量易读。资源围绕WMI服务与win32com.client模块展开,演示了连接远程计算机、调用Win32_ComputerSystem的Shutdown方法、遍历IP列表批量下发关机命令的完整流程,并涉及软关机与强制关机的参数差异、管理员权限要求、目标机远程管理配置以及异常捕获与重试等健壮性处理。目前已有897人学习下载,适合希望快速掌握Windows远程管理脚本编写、提升批量设备维护效率的读者参考借鉴。

1. 从一台台手动关机到一行命令搞定:这个批量远程关机脚本到底能干什么

机房巡检结束,几十台 Windows 机器还亮着,一台台点开始菜单关机显然不现实。这个项目就是冲着这个场景来的:用 Python 在 Windows 下批量远程关闭局域网内的机器,核心依赖系统自带的shutdown命令和net use建立 IPC 连接,不需要在目标机器上装任何客户端。它适合谁?手里管着几台到几十台 Windows 测试机、实验室公用机、渲染农场的开发者或运维,尤其是那种“没有域控、没有专业运维平台,但就是想让机器按时关掉”的小团队。整个脚本不依赖第三方库,纯标准库加系统命令,拿到就能改,改完就能跑,这也是我当初愿意拆它的原因——没有黑匣子,每一行都能看懂。

2. 环境准备与核心依赖:跑通之前先把这几件事确认了

2.1 运行环境与权限要求

这个脚本对运行环境的要求其实不低,但都是 Windows 自带的机制,不需要额外装东西。首先,运行脚本的机器必须是 Windows,因为shutdown和net use都是 Windows 命令,Linux 下没有对应实现。Python 版本建议 3.6 以上,用到了 f-string 和subprocess.run的capture_output参数。权限方面,当前登录账户必须对目标机器有管理员权限,否则net use建立 IPC 连接时会直接返回“拒绝访问”。常见做法是:运行脚本的账户和目标机器的本地管理员账户同名同密码,或者目标机器开启了相同的凭据缓存。如果目标机器在域里,直接用域账户跑就行;如果是工作组环境,就得在每台目标机器上提前建好同名账户。

提示:工作组环境下,目标机器的防火墙需要放行“文件和打印机共享”以及“Windows Management Instrumentation”相关规则,否则net use连不上。

2.2 目标机器需要开启的服务与端口

远程关机依赖两个关键点:一是 IPC 连接能建立,二是shutdown命令能通过远程过程调用发过去。IPC 连接走的是 SMB 协议,默认端口 445。shutdown命令远程执行时走的是 RPC,动态端口范围通常在 49152 到 65535 之间。很多“连不上”的问题,最后查下来都是 445 端口被防火墙拦了,或者目标机器的“Server”服务没启动。我一般会先在目标机器上跑一遍net share确认 IPC$ 共享存在,再用telnet 目标IP 445测一下端口通不通。如果目标机器是 Windows 10 之后的版本,默认可能关闭了 SMB1,但 IPC$ 走的是 SMB2/3,不受影响,不用特意去开 SMB1。

2.3 依赖清单与目录结构

项目本身没有requirements.txt,因为不需要装任何第三方包。整个目录结构通常是这样:

remote_shutdown/ ├── shutdown_batch.py # 主脚本 ├── hosts.txt # 目标机器列表,一行一个IP或主机名 └── logs/ └── shutdown.log # 运行日志,记录每台机器的执行结果

hosts.txt是纯文本,每行一个目标,支持 IP 也支持主机名,空行和#开头的注释行会被跳过。logs目录如果不存在,脚本里用os.makedirs自动创建。这种“一个脚本加一个列表文件”的结构,好处是改目标不用动代码,直接编辑文本就行,适合非开发人员接手。

3. 核心模块拆解:从读取列表到远程关机的完整链路

3.1 读取目标列表与参数解析

脚本入口先处理命令行参数,支持指定列表文件路径、超时时间、是否强制关机。用argparse标准库,不引入额外依赖。读取列表时做一次清洗,去掉空白和注释。

import argparse import os def parse_args(): parser = argparse.ArgumentParser(description="Windows 批量远程关机") parser.add_argument("-f", "--file", default="hosts.txt", help="目标机器列表文件,默认 hosts.txt") parser.add_argument("-t", "--timeout", type=int, default=10, help="单台机器连接超时秒数,默认 10") parser.add_argument("--force", action="store_true", help="强制关闭,不等待应用程序保存") return parser.parse_args() def load_hosts(path): if not os.path.exists(path): raise FileNotFoundError(f"列表文件不存在: {path}") hosts = [] with open(path, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line or line.startswith("#"): continue hosts.append(line) return hosts

parse_args里三个参数各有用途:--file让不同项目可以维护各自的机器列表;--timeout控制单台机器的等待上限,避免某台离线机器拖慢整体进度;--force对应shutdown命令的/f参数,强制结束未保存的程序。load_hosts里做了两件事:检查文件存在性,以及过滤空行和注释。这里用utf-8编码读取,是因为有些机器名可能包含中文,虽然不常见,但加上更稳妥。

3.2 建立 IPC 连接与执行关机命令

这是整个脚本最核心的部分。Windows 下远程关机不能直接对 IP 执行shutdown,必须先通过net use建立到目标机器 IPC$ 的认证连接,然后才能发关机指令。连接和关机都通过subprocess.run调用系统命令完成。

import subprocess import logging def connect_ipc(host, timeout): """建立到目标机器 IPC$ 的连接""" cmd = ["net", "use", f"\\\\{host}\\IPC$", "/user:Administrator"] try: result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) if result.returncode != 0: # 如果已经存在连接,net use 会报错,但实际可用 if "已存在" in result.stderr or "already" in result.stderr.lower(): return True logging.warning(f"{host} IPC连接失败: {result.stderr.strip()}") return False return True except subprocess.TimeoutExpired: logging.error(f"{host} 连接超时({timeout}s)") return False def remote_shutdown(host, force=False): """向目标机器发送关机指令""" cmd = ["shutdown", "/s", "/t", "0", "/m", f"\\\\{host}"] if force: cmd.append("/f") try: result = subprocess.run(cmd, capture_output=True, text=True, timeout=15) if result.returncode == 0: logging.info(f"{host} 关机指令已发送") return True logging.error(f"{host} 关机失败: {result.stderr.strip()}") return False except subprocess.TimeoutExpired: logging.error(f"{host} 关机命令超时") return False

connect_ipc里的/user:Administrator是硬编码的,实际使用时需要改成目标机器上存在的管理员账户。如果目标机器账户不同,可以在hosts.txt里用IP,用户名,密码的格式扩展,但原项目没做这么复杂,保持简单。net use返回非零不一定代表失败,如果之前已经建立过连接,它会提示“已存在”,这种情况直接当作成功处理。remote_shutdown里的/t 0表示立即关机,/m \\\\host指定目标机器。注意shutdown命令的/m参数要求当前账户对目标机器有管理员权限,且目标机器的远程注册表服务可访问。

3.3 日志记录与结果汇总

每台机器的执行结果都要落盘,方便事后排查哪台没关成功。日志用标准库logging,同时输出到文件和控制台。

def setup_logging(log_dir="logs"): os.makedirs(log_dir, exist_ok=True) log_file = os.path.join(log_dir, "shutdown.log") logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[ logging.FileHandler(log_file, encoding="utf-8"), logging.StreamHandler() ] ) def main(): args = parse_args() setup_logging() hosts = load_hosts(args.file) success, fail = 0, 0 for host in hosts: if connect_ipc(host, args.timeout): if remote_shutdown(host, args.force): success += 1 else: fail += 1 else: fail += 1 logging.info(f"执行完成: 成功 {success} 台, 失败 {fail} 台")

setup_logging里同时挂了FileHandler和StreamHandler,这样跑的时候能看到实时输出,跑完还能翻日志。main函数里对每台机器先连 IPC 再发关机指令,两步都成功才算成功。最后汇总成功和失败的数量。这里没有做并发,因为关机操作本身很快,几十台机器串行也就一两分钟,并发反而容易触发目标机器的连接数限制。

4. 避坑与常见问题:这几处翻车点我替你踩过了

4.1 报“拒绝访问”但账户密码明明是对的

现象:net use返回“系统发生 5 错误,拒绝访问”。原因通常有三个:一是目标机器的本地安全策略里“账户:使用空白密码的本地账户只允许进行控制台登录”被启用了,空密码账户无法远程连接;二是目标机器的“网络访问:本地账户的共享和安全模型”设置成了“仅来宾”,导致管理员账户也被降权;三是当前账户和目标机器账户同名但密码不同。解决:在目标机器上把空密码策略禁用,把共享安全模型改成“经典”,或者统一账户密码。

4.2 关机命令返回成功但机器没关

现象:shutdown命令返回码为 0,日志显示“关机指令已发送”,但目标机器依然亮着。原因一般是目标机器上有程序阻止了关机,而脚本没加/f参数。Windows 默认会给应用程序最多 5 秒的保存时间,如果有程序弹窗询问是否保存,关机就会被挂起。解决:运行脚本时加上--force,对应shutdown的/f参数,强制结束进程。但要注意,强制关机可能导致未保存的数据丢失,生产环境慎用。

4.3 部分机器连不上但 ping 得通

现象:ping目标 IP 正常,但net use超时或报错。原因通常是目标机器的 445 端口被防火墙拦截,或者“Server”服务被禁用。Windows 防火墙默认对非域网络会阻止文件和打印机共享。解决:在目标机器上执行netsh advfirewall firewall set rule group="文件和打印机共享" new enable=Yes,或者手动放行 445 端口。如果目标机器是 Windows 10 家庭版,可能本身就不支持完整的 SMB 服务端功能,这种情况只能换方案。

4.4 脚本跑完残留 IPC 连接

现象:多次运行脚本后,net use列表里堆积了大量到不同机器的 IPC$ 连接,导致后续连接报“已达到计算机的连接数最大值”。原因:net use建立的连接默认会保持,直到会话结束或手动断开。解决:在remote_shutdown成功后加一句subprocess.run(["net", "use", f"\\\\{host}\\IPC$", "/delete", "/y"])主动断开。或者在脚本开头统一清理一次net use * /delete /y,但这样会断开所有已有连接,需要评估影响。

4.5 目标机器关机后脚本卡住

现象:脚本在发送关机指令后长时间无响应,最后超时。原因:shutdown命令在目标机器开始关机流程后,RPC 连接可能不会立即返回,导致subprocess.run等待。解决:给remote_shutdown里的subprocess.run设置一个较短的timeout,比如 15 秒,超时后直接当作成功处理,因为指令已经发出去了。或者用subprocess.Popen不等待返回,但这样拿不到返回码,需要权衡。

5. 二次开发与改造思路:从能跑到好用还差这几步

5.1 支持多账户与凭据文件

原脚本把用户名硬编码成Administrator,实际环境里目标机器的管理员账户可能各不相同。改造思路是在hosts.txt里支持IP,用户名,密码的格式,读取时解析成字典,connect_ipc根据每台机器的凭据动态拼接net use命令。密码不建议明文写在列表里,可以用keyring库存到 Windows 凭据管理器,或者用一个单独的加密配置文件。我一般会加一个--cred-file参数,指向一个 JSON 文件,格式是{"192.168.1.10": {"user": "admin", "pass": "xxx"}},脚本启动时加载到内存,不落盘明文。

5.2 加入并发与超时控制

串行执行在几十台机器时还能接受,上百台就明显慢了。可以用concurrent.futures.ThreadPoolExecutor做并发,每个线程处理一台机器,主线程汇总结果。但要注意两点:一是并发数不要超过目标网络能承受的连接数,一般设 10 到 20 个线程;二是net use命令本身不是线程安全的,多个线程同时操作 IPC 连接可能冲突,稳妥做法是每台机器独立连接、独立断开,不共享连接。下面是一个改造后的并发骨架:

from concurrent.futures import ThreadPoolExecutor, as_completed def shutdown_one(host, timeout, force): if connect_ipc(host, timeout): ok = remote_shutdown(host, force) # 主动断开,避免连接堆积 subprocess.run(["net", "use", f"\\\\{host}\\IPC$", "/delete", "/y"], capture_output=True) return host, ok return host, False def main_concurrent(hosts, timeout, force, max_workers=10): results = [] with ThreadPoolExecutor(max_workers=max_workers) as pool: futures = {pool.submit(shutdown_one, h, timeout, force): h for h in hosts} for future in as_completed(futures): host, ok = future.result() results.append((host, ok)) logging.info(f"{host} {'成功' if ok else '失败'}") return results

max_workers控制并发上限,默认 10 个线程。每个线程里先连 IPC,再发关机指令,最后主动断开连接。as_completed按完成顺序收集结果,不用等所有线程都跑完才处理。这样改造后,100 台机器的执行时间大概能从几分钟压缩到十几秒。

5.3 增加关机前检查与延迟关机

直接关机太粗暴,有时候目标机器上还有人在用。可以在关机前加一个检查步骤,比如通过 WMI 查询目标机器是否有活跃的交互式登录会话,或者检查 CPU 占用率是否低于某个阈值。Python 里可以用wmi库(需要pywin32)远程查询,但这就引入了第三方依赖。更轻量的做法是先用ping确认机器在线,再用tasklist /s \\\\host /u user /p pass查看是否有特定进程在跑,比如chrome.exe或notepad.exe。如果检测到活跃进程,就跳过这台机器,记录到日志里,等下一轮再处理。延迟关机可以用shutdown /s /t 300实现,给用户 5 分钟缓冲时间,同时发一条msg消息通知。

5.4 验证改造效果的方法

改完之后怎么确认没问题?我一般分三步验证。第一步,用一台测试机跑单机模式,确认net use和shutdown命令能正常执行,日志里能看到成功记录。第二步,用三到五台机器跑并发模式,观察日志里每台机器的状态,确认没有连接冲突和超时。第三步,故意把其中一台机器的 IP 改成不存在的地址,看脚本是否能正确记录失败并继续处理其他机器,而不是整个卡住。最后,检查net use列表,确认脚本跑完后没有残留连接。这套流程走下来,基本能覆盖大部分边界情况。

从那以后我每次改完这类远程操作脚本,都会先在一台闲置机器上跑一遍完整流程,确认关机、日志、连接清理三个环节都正常,再放到正式环境。远程操作这东西,翻车往往不是因为代码逻辑错,而是环境差异和权限细节没对齐。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 20:23:33

21-PEFT全景-为什么需要它六类方法一张表

PEFT 全景:为什么需要它,六类方法一张表看完 【大模型面试通关手册 第 21 篇】 本篇覆盖:PEFT 的三条成本约束、四种分类法与其"最终形态"、八种代表方法的定位、参数口径的三种算法、"FT vs LoRA"两处矛盾的变量分析、显存与速度对照表的正确读法、选…

作者头像 李华
网站建设 2026/10/23 20:21:51

Gmsh转Exodus II:近场动力学仿真的网格格式转换实战

简介:这是一份将Gmsh网格转换为Exodus II格式的Python开源工具,专门解决Gmsh生成网格与Peridigm等仿真程序所需Exodus II文件不互通的问题,适合从事近场动力学、无网格仿真及ParaView后处理的科研与工程人员使用。工具通过convert.py脚本完成…

作者头像 李华
网站建设 2026/10/23 20:21:24

SpringBoot与Hadoop在农业环境监测系统中的应用

1. 项目背景与核心价值农业环境管理在现代化农业生产中扮演着越来越重要的角色。传统农业环境监测往往依赖人工记录和分散的数据处理方式,这种方式效率低下且难以进行大规模数据分析。我们团队开发的这套系统,正是为了解决这些痛点问题。这个平台最核心的…

作者头像 李华
网站建设 2026/10/23 20:18:03

Eplan 2.9项目文件打不开?从文件结构到备份恢复的完整排查指南

简介:适用于Eplan 2.9的长期解密文件,面向电气设计工程师和经常使用EPLAN软件的各类用户,旨在解决常规授权每隔30天就需重新替换的麻烦,提供可一直使用的解密方案。压缩包体积仅2.61MB,共18个文件,其中包括…

作者头像 李华