资讯动态

Python 在 Windows 下批量远程关机:WMI 与 shutdown 命令实战

发布时间:2026/10/23 17:28:16 来源:尧图企业网站定制
简介这是一份面向IT运维人员与Python学习者的Windows远程批量关机脚本资源针对多台设备统一关机、故障排查与日常维护场景提供可直接参考的自动化实现思路。压缩包共3个文件包含1个py脚本与2个txt说明文档整体仅923B体积轻巧便于快速取用脚本以win32com.client调用WMI服务连接远程主机通过Win32_ComputerSystem的Shutdown方法执行软关机或强制关机并支持遍历IP列表完成批量操作说明文档则补充权限配置与使用要点。资源已有897人学习下载适合需要批量管理终端、希望掌握WMI远程调用与异常处理技巧的读者可据此快速搭建脚本框架理解用户名密码鉴权、目标机远程管理策略设置及重试超时等健壮性优化方向提升多设备运维效率。1. 批量远程关机这件事Python 在 Windows 下到底能省多少事机房巡检完最后一批机器凌晨两点半你手里攥着一张 Excel 表上面列着三十多台 Windows 主机的 IP、账号、密码。一台一台远程桌面连过去点关机点完最后一台天都亮了。这种场景在实验室、测试机房、临时搭建的渲染农场里太常见了。Python 在 Windows 下做自动远程批量关机核心思路就两条路一条走 WMIWindows Management Instrumentation一条走系统自带的 shutdown 命令配合凭据。两条路都不需要装额外服务端只要目标机器开了对应的端口和权限就能跑。适合谁手头有十几台以上 Windows 机器需要统一关停、又不想逐台操作的运维或开发。下面把我自己踩过的坑和能直接抄的代码拆开讲。2. 两条技术路线选型WMI 与 shutdown 命令的取舍2.1 WMI 方案适合需要精细控制的场景WMI 是 Windows 原生的管理接口Python 通过pywin32库调用它。好处是能拿到目标机器的详细状态比如当前登录用户、运行中的进程甚至可以在关机前做一次条件判断。坏处是依赖 DCOM 配置跨网段或者目标机器防火墙策略严格时连接容易被拒。我一般会先用 WMI 做一次探测确认目标机器可达且凭据有效再决定是否执行关机。探测代码如下import wmi def check_host(ip, username, password): 通过 WMI 连接目标主机返回系统信息或 None ip: 目标主机 IP username: 管理员账号 password: 对应密码 try: # 指定目标 IP、账号、密码建立 WMI 连接 conn wmi.WMI( computerip, userusername, passwordpassword, namespaceroot\\cimv2 # 默认命名空间查系统信息够用 ) # 拿操作系统信息作为连通性验证 os_info conn.Win32_OperatingSystem()[0] return os_info.Caption # 例如 Microsoft Windows 10 专业版 except Exception as e: print(f[FAIL] {ip} 连接失败: {e}) return None这段代码的逻辑很直白用wmi.WMI()建立连接namespace参数指定root\cimv2这是查大多数硬件和系统信息的标准入口。Win32_OperatingSystem()返回一个列表取第一个元素的Caption属性就是系统版本。如果连接失败会抛异常捕获后打印失败原因。参数方面computer填 IP 或主机名都行user建议用域名\账号格式比如WORKGROUP\Administrator不写域名有时会认证失败。2.2 shutdown 命令方案轻量、快、但控制粒度粗Windows 自带的shutdown.exe支持远程关机语法是shutdown /s /m \\目标IP /t 0 /f。Python 里用subprocess调它就行。这个方案不依赖 DCOM走的是 RPC目标机器只要开了“文件和打印机共享”以及远程注册表服务就能通。缺点是没法在关机前做复杂判断而且凭据传递要靠net use先建立 IPC 连接。import subprocess def shutdown_via_cmd(ip, username, password): 先用 net use 建立 IPC 连接再调用 shutdown 命令 # 建立 IPC$ 连接为后续 shutdown 提供凭据 subprocess.run( fnet use \\\\{ip}\\IPC$ /user:{username} {password}, shellTrue, capture_outputTrue, textTrue ) # 执行远程关机/t 0 表示立即/f 强制关闭应用 result subprocess.run( fshutdown /s /m \\\\{ip} /t 0 /f, shellTrue, capture_outputTrue, textTrue ) # 用完删除连接避免凭据残留 subprocess.run(fnet use \\\\{ip}\\IPC$ /delete /y, shellTrue) return result.returncodenet use那一步是关键没有它shutdown /m会报“拒绝访问”。/user:后面跟账号密码直接跟在后面。capture_outputTrue把输出抓回来方便判断是否成功。/t 0是倒计时零秒/f强制结束未保存的应用。最后一定要net use /delete否则多次执行会累积连接导致“多重连接”错误。2.3 怎么选看目标机器数量和网络环境如果目标机器在同一个域里WMI 方案更稳因为域账号认证走 Kerberos不需要明文传密码。如果是工作组环境机器数量在 20 台以内shutdown 命令方案更快落地代码量也少。超过 50 台建议用 WMI 加线程池并发但要注意 DCOM 的并发连接数限制一般开到 10 到 15 个线程就差不多了再高容易触发 RPC 超时。3. 批量执行框架从单台到多台的工程化改造3.1 读取主机清单与凭据管理硬编码 IP 和密码是大忌。我一般用 CSV 存主机列表密码单独放一个文件或者用环境变量。CSV 格式如下ip,username,password 192.168.1.101,Administrator,Pass123! 192.168.1.102,Administrator,Pass123!读取代码import csv def load_hosts(csv_path): 从 CSV 加载主机列表返回字典列表 hosts [] with open(csv_path, newline, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: hosts.append({ ip: row[ip].strip(), username: row[username].strip(), password: row[password].strip() }) return hostsDictReader自动把表头映射成键strip()去掉可能存在的空格。密码字段如果不想明文存可以改成读环境变量比如os.environ.get(fPASS_{row[ip]})这样 CSV 里只留 IP 和账号。3.2 并发控制与超时设置串行关机太慢30 台机器每台等 5 秒就是两分半。用concurrent.futures.ThreadPoolExecutor并发但必须设超时否则一台卡死的机器会拖垮整个任务。from concurrent.futures import ThreadPoolExecutor, as_completed import time def batch_shutdown(hosts, max_workers10, timeout15): 并发批量关机 hosts: 主机字典列表 max_workers: 并发线程数建议 10-15 timeout: 单台超时秒数 results {} with ThreadPoolExecutor(max_workersmax_workers) as executor: # 提交任务future 与 ip 建立映射 future_map { executor.submit(shutdown_via_cmd, h[ip], h[username], h[password]): h[ip] for h in hosts } for future in as_completed(future_map, timeouttimeout * len(hosts)): ip future_map[future] try: code future.result(timeouttimeout) results[ip] 成功 if code 0 else f返回码 {code} except Exception as e: results[ip] f异常: {e} return resultsmax_workers控制同时关机的机器数设太大目标网络会拥塞设太小又失去并发意义。as_completed的timeout参数是总超时我一般设成单台超时 × 机器数防止某台机器无响应导致主线程永久阻塞。future.result(timeouttimeout)是单台超时超过就抛TimeoutError记录异常继续处理下一台。3.3 执行结果记录与重试机制关机这种操作失败一次就得人工补所以结果必须落盘。我习惯写一个简单的日志文件格式是时间戳,IP,状态。重试逻辑只对“连接超时”和“返回码 5拒绝访问”以外的错误重试一次因为拒绝访问重试也没用得先修权限。import logging logging.basicConfig( filenameshutdown_log.txt, levellogging.INFO, format%(asctime)s,%(message)s ) def shutdown_with_retry(ip, username, password, retries1): 带一次重试的关机封装 for attempt in range(retries 1): code shutdown_via_cmd(ip, username, password) if code 0: logging.info(f{ip},成功) return True elif code 5: logging.error(f{ip},拒绝访问不重试) return False else: logging.warning(f{ip},第{attempt1}次失败返回码{code}) time.sleep(2) # 等两秒再试 logging.error(f{ip},重试后仍失败) return Falselogging模块直接输出 CSV 格式的日志方便后续用 Excel 打开筛选。retries1表示最多试两次。time.sleep(2)给目标机器一点缓冲时间尤其是刚开机不久的系统服务还没完全起来。4. 避坑指南远程关机最常见的五个翻车点4.1 现象报“拒绝访问”错误码 5原因目标机器的账号不是管理员组或者 UAC 远程限制没关。工作组环境下即使账号是 Administrator如果目标机器开了 UAC 远程限制也会拒绝。解决在目标机器上把LocalAccountTokenFilterPolicy注册表项设为 1。命令是reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f。这个操作需要重启目标机器或者重启相关服务才生效。4.2 现象WMI 连接超时但 ping 得通原因目标机器防火墙拦了 DCOM 的端口。WMI 走的是 TCP 135 和动态端口范围很多安全策略只开了 135动态端口没放行。解决在目标机器防火墙里放行“Windows Management Instrumentation (WMI)”入站规则。如果没法改防火墙换 shutdown 命令方案它走 RPC over SMB通常 445 端口是通的。4.3 现象shutdown 命令返回“系统找不到指定的文件”原因net use那一步没成功建立 IPC 连接或者密码里有特殊字符被 shell 转义了。解决检查net use的返回输出确认连接建立。密码里如果有、|、这类字符用双引号把密码包起来或者改用subprocess.run的列表参数形式避免 shell 解析。4.4 现象并发执行时部分机器报“多重连接”原因同一个目标 IP 被多个线程同时net useWindows 不允许同一目标有多重凭据连接。解决在shutdown_via_cmd里加一个简单的文件锁或者把并发数降到 5 以下。更彻底的办法是改用 WMI 方案WMI 不依赖 IPC 连接没这个问题。4.5 现象关机命令发出去了但机器没关原因目标机器上有未保存的文档/f参数虽然强制关闭应用但某些系统进程会阻止关机。或者目标机器设置了“关机需要等待用户响应”。解决在关机前先用 WMI 查一下Win32_Process里有没有notepad、excel这类进程有的话先发消息提醒。或者改用shutdown /s /m \\IP /t 30 /c 系统将在30秒后关闭给用户一个保存的机会。5. 进阶技巧用 WMI 事件订阅做关机前检查前面讲的都是“直接关”但有些场景下你希望目标机器在关机前先执行一段清理脚本比如删除临时文件、上传日志。WMI 支持事件订阅可以在目标机器上注册一个关机前触发的事件消费者。这个操作稍微复杂但一次注册长期有效。import wmi def register_shutdown_script(ip, username, password, script_path): 在目标机器注册关机前执行的脚本 script_path: 目标机器上的本地脚本路径如 C:\\cleanup.bat conn wmi.WMI(computerip, userusername, passwordpassword) # 查询已存在的消费者避免重复注册 existing conn.Win32_SystemStartup() # 创建命令执行消费者 startup conn.Win32_SystemStartup.new() # 绑定到关机事件 # 注意这里用 Win32_SystemShutdown 事件类 consumer conn.Win32_SystemShutdown.new() # 实际绑定需要调用 __EventFilter 和 __EventConsumer # 简化写法直接用 Win32_Process 在关机前启动脚本 # 更稳妥的方式是用组策略或计划任务 print(f请在 {ip} 上手动创建关机计划任务触发条件选“关机时”)上面这段代码其实是个半成品因为 WMI 事件订阅的完整实现需要操作__EventFilter、__EventConsumer和__FilterToConsumerBinding三个类代码量不小。我一般直接建议用 Windows 自带的计划任务在目标机器上创建一个任务触发器选“当计算机即将关闭时”操作指向你的清理脚本。这个用schtasks命令就能远程创建schtasks /create /s 192.168.1.101 /u Administrator /p Pass123! /tn PreShutdownCleanup /tr C:\cleanup.bat /sc onshutdown /f/sc onshutdown就是关机时触发/f强制覆盖同名任务。这个命令比写 WMI 事件订阅简单得多而且稳定。验证方法在目标机器上手动执行shutdown /s /t 60然后观察C:\cleanup.bat是否在关机前运行。可以先把脚本内容改成写一个时间戳文件确认触发时机。从那以后我每次做批量关机前都会先拿一台测试机跑一遍完整流程确认凭据、防火墙、脚本触发都正常再推到生产环境。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑